diff --git a/.build/build-accord.xml b/.build/build-accord.xml
new file mode 100644
index 0000000000..eeadf4dd18
--- /dev/null
+++ b/.build/build-accord.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.build/build-checkstyle.xml b/.build/build-checkstyle.xml
index af5867e4aa..0484e4098c 100644
--- a/.build/build-checkstyle.xml
+++ b/.build/build-checkstyle.xml
@@ -19,7 +19,7 @@
-
+
@@ -45,7 +45,7 @@
-
+
diff --git a/.build/build-rat.xml b/.build/build-rat.xml
index 2f6f5c7156..9333d2b8da 100644
--- a/.build/build-rat.xml
+++ b/.build/build-rat.xml
@@ -78,6 +78,7 @@
+
diff --git a/.build/build-resolver.xml b/.build/build-resolver.xml
index 5a1a653086..29031b33a1 100644
--- a/.build/build-resolver.xml
+++ b/.build/build-resolver.xml
@@ -178,7 +178,7 @@
-
+
@@ -206,7 +206,7 @@
-
+
diff --git a/.build/cassandra-build-deps-template.xml b/.build/cassandra-build-deps-template.xml
index 4ec59cdf2d..c6b56955e0 100644
--- a/.build/cassandra-build-deps-template.xml
+++ b/.build/cassandra-build-deps-template.xml
@@ -155,5 +155,10 @@
org.bouncycastlebcutil-jdk18on
+
+ org.apache.cassandra
+ cassandra-accord
+ tests
+
diff --git a/.build/cassandra-deps-template.xml b/.build/cassandra-deps-template.xml
index 20223c3169..be58faa2f4 100644
--- a/.build/cassandra-deps-template.xml
+++ b/.build/cassandra-deps-template.xml
@@ -116,6 +116,10 @@
org.mindrotjbcrypt
+
+ org.apache.cassandra
+ cassandra-accord
+ io.airliftairline
diff --git a/.build/git/git-hooks/post-checkout/100-update-submodules.sh b/.build/git/git-hooks/post-checkout/100-update-submodules.sh
new file mode 100755
index 0000000000..b495ed0860
--- /dev/null
+++ b/.build/git/git-hooks/post-checkout/100-update-submodules.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Redirect output to stderr.
+exec 1>&2
+
+#set -o xtrace
+set -o errexit
+set -o pipefail
+set -o nounset
+
+bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
+
+_main() {
+ # In case the usage happens at a different layer, make sure to cd to the toplevel
+ local root_dir
+ root_dir="$(git rev-parse --show-toplevel)"
+ cd "$root_dir"
+
+ if [[ ! -e .gitmodules ]]; then
+ # nothing to see here, look away!
+ return 0
+ fi
+ git submodule update --init --recursive
+}
+
+_main "$@"
diff --git a/.build/git/git-hooks/post-switch b/.build/git/git-hooks/post-switch
new file mode 120000
index 0000000000..5513d1deed
--- /dev/null
+++ b/.build/git/git-hooks/post-switch
@@ -0,0 +1 @@
+post-checkout
\ No newline at end of file
diff --git a/.build/git/git-hooks/pre-commit/100-verify-submodules-pushed.sh b/.build/git/git-hooks/pre-commit/100-verify-submodules-pushed.sh
new file mode 100755
index 0000000000..c54099ac0f
--- /dev/null
+++ b/.build/git/git-hooks/pre-commit/100-verify-submodules-pushed.sh
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##
+## When working with submodules the top level project (Apache Cassandra) needs to commit all submodule
+## changes so the top level knows what SHA to use. When working in a development environment it is
+## common that multiple commits will exist in both projects, if the submodule has its history
+## rewritten, then historic top level commits are no longer valid unless the SHAs are pushed to a
+## remote repo; this is what the script attempts to do, make sure all SHAs added to the
+## Apache Cassandra are backed up to a remote repo to make the Cassandra SHA buildable.
+##
+
+# Redirect output to stderr.
+exec 1>&2
+
+
+#set -o xtrace
+set -o errexit
+set -o pipefail
+set -o nounset
+
+bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
+
+_log() {
+ echo -e "[pre-commit]\t$*"
+}
+
+error() {
+ _log "$@" 1>&2
+ exit 1
+}
+
+# Status Table
+# A Added
+# C Copied
+# D Deleted
+# M Modified
+# R Renamed
+# T Type Changed (i.e. regular file, symlink, submodule, …<200b>)
+# U Unmerged
+# X Unknown
+# B Broken
+_main() {
+ # In case the usage happens at a different layer, make sure to cd to the toplevel
+ local root_dir
+ root_dir="$(git rev-parse --show-toplevel)"
+ cd "$root_dir"
+
+ [[ ! -e .gitmodules ]] && return 0
+ local enabled=$(git config --bool cassandra.pre-commit.verify-submodules.enabled || echo true)
+ [ "$enabled" == "false" ] && return 0
+ local submodules=( $(git config --file .gitmodules --get-regexp path | awk '{ print $2 }') )
+
+ local is_submodule=false
+ local git_sub_dir
+ local git_sha
+ while read status file; do
+ is_submodule=false
+ for to_check in "${submodules[*]}"; do
+ if [[ "$to_check" == "$file" ]]; then
+ is_submodule=true
+ break
+ fi
+ done
+ if $is_submodule; then
+ local enabled=$(git config --bool cassandra.pre-commit.verify-submodule-${file}.enabled || echo true)
+ [ "$enabled" == "false" ] && continue
+ _log "Submodule detected: ${file} with status ${status}; attempting a push"
+ _log "\tTo disable pushes, run"
+ _log "\t\tgit config --local cassandra.pre-commit.verify-submodules.enabled false"
+ _log "\tOr"
+ _log "\t\tgit config --local cassandra.pre-commit.verify-submodule-${file}.enabled false"
+ set -x
+ git_sub_dir="${file}/.git"
+ branch="$(git config -f .gitmodules "submodule.${file}.branch")"
+ [[ -z "${branch:-}" ]] && error "Submodule ${file} does not define a branch"
+ git_sha="$(git --git-dir "${git_sub_dir}" rev-parse HEAD)"
+ git --git-dir "${git_sub_dir}" fetch origin
+ git --git-dir "${git_sub_dir}" branch "origin/${branch}" --contains "${git_sha}" || error "Git commit ${git_sha} not found in $(git remote get-url origin) on branch ${branch}"
+ fi
+ done < <(git diff --cached --name-status)
+}
+
+_main "$@"
diff --git a/.build/git/git-hooks/pre-push/100-push-submodules.sh b/.build/git/git-hooks/pre-push/100-push-submodules.sh
new file mode 100755
index 0000000000..c3daa95597
--- /dev/null
+++ b/.build/git/git-hooks/pre-push/100-push-submodules.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Redirect output to stderr.
+exec 1>&2
+
+#set -o xtrace
+set -o errexit
+set -o pipefail
+set -o nounset
+
+bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
+
+_main() {
+ # In case the usage happens at a different layer, make sure to cd to the toplevel
+ local root_dir
+ root_dir="$(git rev-parse --show-toplevel)"
+ cd "$root_dir"
+
+ if [[ ! -e .gitmodules ]]; then
+ # nothing to see here, look away!
+ return 0
+ fi
+
+ local -r cmd='
+branch="$(git rev-parse --abbrev-ref HEAD)"
+[[ "$branch" == "HEAD" ]] && exit 0
+
+default_remote="$(git config --local --get branch."${branch}".remote || true)"
+remote="${default_remote:-origin}"
+
+git push --atomic "$remote" "$branch"
+'
+ git submodule foreach --recursive "$cmd"
+}
+
+_main "$@"
diff --git a/.build/git/install-git-defaults.sh b/.build/git/install-git-defaults.sh
new file mode 100755
index 0000000000..00f1dc435d
--- /dev/null
+++ b/.build/git/install-git-defaults.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#set -o xtrace
+set -o errexit
+set -o pipefail
+set -o nounset
+
+bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
+
+install_template_script() {
+ local -r name="$1"
+ local -r d_dir="$2"
+
+ cat < "$name"
+#!/usr/bin/env bash
+
+# This script is autogenerated by the Apache Cassandra build; DO NOT CHANGE!
+# When this script is not found it will be installed automatically by the build
+# If an existing script is found, that script will be reloated under ${d_dir} as 000-original.sh
+
+# Redirect output to stderr.
+exec 1>&2
+
+# Find all scripts to run
+for path in \$(find "$d_dir" -name '*.sh' | perl -e "print sort{(split '/', \\\$a)[-1] <=> (split '/', \\\$b)[-1]}<>"); do
+ "\$path" "\$@"
+done
+EOF
+ chmod a+x "$name"
+}
+
+install_hook() {
+ local -r git_dir="$1"
+ local -r hooks_dir="${git_dir}/hooks"
+ local -r name="$2"
+ local -r d_dir="${hooks_dir}/${name}.d"
+ local -r trigger_on_install=$3
+
+ mkdir "${d_dir}" &> /dev/null || true
+ local -r script_name="${hooks_dir}/${name}"
+ local installed=true
+ if [[ -e "$script_name" ]]; then
+ # was the script already installed?
+ if ! grep "This script is autogenerated by the Apache Cassandra build" "$script_name" &> /dev/null ; then
+ echo "$script_name found, but was not generated by the Apache Cassandra build; please remove or move to ${d_dir}/000-original.sh; creating and moving to ${d_dir} will cause it to run as expected, but won't conflict with hooks this build adds" 1>&2
+ exit 1
+ else
+ installed=false
+ fi
+ fi
+ # install all hooks
+ cp "$bin"/git-hooks/"${name}"/* "$d_dir"/
+
+ # install coordinator hook
+ install_template_script "$script_name" "$d_dir"
+ if $installed && $trigger_on_install ; then
+ echo "Running script $script_name"
+ "$script_name"
+ fi
+}
+
+_install_hooks() {
+ local git_dir
+ # make sure to use --git-common-dir and not --git-dir to support worktrees
+ git_dir="$(git rev-parse --git-common-dir 2> /dev/null || true)"
+ if [[ -z "${git_dir:-}" ]]; then
+ # not in a git repo, noop
+ return 0
+ fi
+
+ # make sure hooks directory exists; does not exist by default for worktrees
+ mkdir -p "${git_dir}/hooks" &> /dev/null || true
+
+ install_hook "$git_dir" "post-checkout" true
+ install_hook "$git_dir" "post-switch" false
+ install_hook "$git_dir" "pre-commit" false
+ install_hook "$git_dir" "pre-push" false
+}
+
+_git_config_set() {
+ local -r name="$1"
+ # only care about rc
+ git config --local --get "$name" &> /dev/null
+}
+
+_install_configs() {
+ # when doing pull, this makes sure submodules are updated
+ _git_config_set submodule.recurse || git config --local submodule.recurse true
+}
+
+_main() {
+ local git_dir
+ # make sure to use --git-common-dir and not --git-dir to support worktrees
+ git_dir="$(git rev-parse --git-common-dir 2> /dev/null || true)"
+ # not in a git repo, noop
+ [[ -z "${git_dir:-}" ]] && return 0
+
+ _install_configs
+ _install_hooks
+}
+
+_main "$@"
diff --git a/.build/parent-pom-template.xml b/.build/parent-pom-template.xml
index aafd527bad..2bb3c26927 100644
--- a/.build/parent-pom-template.xml
+++ b/.build/parent-pom-template.xml
@@ -715,6 +715,42 @@
jbcrypt0.4
+
+ org.apache.cassandra
+ cassandra-accord
+ @version@
+
+
+ org.apache.cassandra
+ cassandra-all
+
+
+
+
+ org.apache.cassandra
+ cassandra-accord
+ @version@
+ tests
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ org.apache.cassandra
+ cassandra-all
+
+
+ io.airliftairline
diff --git a/.build/sh/bump-accord.sh b/.build/sh/bump-accord.sh
new file mode 100755
index 0000000000..43a476f3ed
--- /dev/null
+++ b/.build/sh/bump-accord.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#set -o xtrace
+set -o errexit
+set -o pipefail
+set -o nounset
+
+_main() {
+ local home
+ home="$(git rev-parse --show-toplevel)"
+ cd "$home"
+
+ git submodule status modules/accord
+ echo "Is this the correct SHA? [y/n; default=y]"
+ read correct
+ if [[ "${correct:-y}" != "y" ]]; then
+ echo "Please update Accord's SHA and try again"
+ exit 1
+ fi
+ git commit -m "Change Accord to $(cd modules/accord; git log -1 --format='%h: %B')" modules/accord
+}
+
+_main "$@"
diff --git a/.build/sh/change-submodule-accord.sh b/.build/sh/change-submodule-accord.sh
new file mode 100755
index 0000000000..997db3dc2c
--- /dev/null
+++ b/.build/sh/change-submodule-accord.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#set -o xtrace
+set -o errexit
+set -o pipefail
+set -o nounset
+
+bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
+
+"$bin"/change-submodule.sh modules/accord 'https://github.com/apache/cassandra-accord.git' trunk
diff --git a/.build/sh/change-submodule.sh b/.build/sh/change-submodule.sh
new file mode 100755
index 0000000000..6ab2d3795a
--- /dev/null
+++ b/.build/sh/change-submodule.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#set -o xtrace
+set -o errexit
+set -o pipefail
+set -o nounset
+
+_usage() {
+ cat <&2
+ exit 1
+}
+
+_usage() {
+ cat <
+```
+
+When changes are made to a submodule (such as to accord), you need to commit and update the reference in Apache Cassandra
+
+```
+$ (cd modules/accord ; git commit -am 'Saving progress')
+$ .build/sh/bump-accord.sh
+```
+
+## Commit and Merge Process
+
+Due to the nature of submodules, the changes to the submodules must be committed and pushed before the changes to Apache Cassandra; these are different repositories so git's `--atomic` does not prevent conflicts from concurrent merges; the basic process is as follows:
+
+* Follow the normal merge process for the submodule
+* Update Apache Cassandra's submodule entry to point to the newly committed change; follow the Accord example below for an example
+
+```
+$ .build/sh/change-submodule-accord.sh
+$ .build/sh/bump-accord.sh
+```
+
# Useful Links
- How you can contribute to Apache Cassandra [presentation](http://www.slideshare.net/yukim/cassandrasummit2013) by Yuki Morishita
diff --git a/accord_demo.txt b/accord_demo.txt
new file mode 100644
index 0000000000..b883451522
--- /dev/null
+++ b/accord_demo.txt
@@ -0,0 +1,19 @@
+
+ccm create accord-cql-poc -n 3
+ccm start
+
+bin/cqlsh -e "create keyspace ks with replication={'class':'SimpleStrategy', 'replication_factor':3};"
+bin/cqlsh -e "create table ks.tbl1 (k int primary key, v int);"
+bin/cqlsh -e "create table ks.tbl2 (k int primary key, v int);"
+
+bin/nodetool -h 0000:0000:0000:0000:0000:ffff:7f00:0001 -p 7100 createepochunsafe
+bin/nodetool -h 0000:0000:0000:0000:0000:ffff:7f00:0001 -p 7200 createepochunsafe
+bin/nodetool -h 0000:0000:0000:0000:0000:ffff:7f00:0001 -p 7300 createepochunsafe
+
+BEGIN TRANSACTION
+ LET row1 = (SELECT * FROM ks.tbl1 WHERE k = 1);
+ SELECT row1.v;
+ IF row1 IS NULL THEN
+ INSERT INTO ks.tbl1 (k, v) VALUES (1, 2);
+ END IF
+COMMIT TRANSACTION;
\ No newline at end of file
diff --git a/build.xml b/build.xml
index c1b9d74b96..563ac70ea2 100644
--- a/build.xml
+++ b/build.xml
@@ -100,6 +100,8 @@
the user specifies the tmp.dir property -->
+
+
@@ -109,8 +111,12 @@
+
+
+
+
@@ -396,6 +402,7 @@
+
@@ -527,7 +534,8 @@
-
+
+
@@ -973,6 +981,9 @@
+
+
+
@@ -992,6 +1003,7 @@
+
@@ -2061,6 +2073,7 @@
+
+
+
+
+
+
+
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index c813bf530a..89582a23de 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -2199,6 +2199,9 @@ drop_compact_storage_enabled: false
# Whether or not USE is allowed. This is enabled by default to avoid failure on upgrade.
#use_statements_enabled: true
+# Enables the execution of Accord (multi-key) transactions on this node.
+accord_transactions_enabled: false
+
# When the client triggers a protocol exception or unknown issue (Cassandra bug) we increment
# a client metric showing this; this logic will exclude specific subnets from updating these
# metrics
diff --git a/ide/idea-iml-file.xml b/ide/idea-iml-file.xml
index 13e66fa613..1d189db8d6 100644
--- a/ide/idea-iml-file.xml
+++ b/ide/idea-iml-file.xml
@@ -49,6 +49,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -56,6 +66,8 @@
+
+
@@ -63,12 +75,17 @@
+
+
+
+
+
@@ -76,6 +93,9 @@
+
+
+
diff --git a/ide/idea/vcs.xml b/ide/idea/vcs.xml
index 81872fd3f1..a5367a526e 100644
--- a/ide/idea/vcs.xml
+++ b/ide/idea/vcs.xml
@@ -2,6 +2,7 @@
+
-
\ No newline at end of file
+
diff --git a/ide/idea/workspace.xml b/ide/idea/workspace.xml
index c5c0e28b96..7f688b3d96 100644
--- a/ide/idea/workspace.xml
+++ b/ide/idea/workspace.xml
@@ -183,24 +183,38 @@
diff --git a/modules/accord b/modules/accord
new file mode 160000
index 0000000000..b9025e5939
--- /dev/null
+++ b/modules/accord
@@ -0,0 +1 @@
+Subproject commit b9025e59395f47535e4ed1fec20b1186cdb07db8
diff --git a/pylib/cqlshlib/cqlhandling.py b/pylib/cqlshlib/cqlhandling.py
index 2cc49fbee4..76a516af80 100644
--- a/pylib/cqlshlib/cqlhandling.py
+++ b/pylib/cqlshlib/cqlhandling.py
@@ -25,10 +25,10 @@ from cqlshlib import pylexotron, util
Hint = pylexotron.Hint
cql_keywords_reserved = {'add', 'allow', 'alter', 'and', 'apply', 'asc', 'authorize', 'batch', 'begin', 'by',
- 'columnfamily', 'create', 'delete', 'desc', 'describe', 'drop', 'entries', 'execute', 'from',
- 'full', 'grant', 'if', 'in', 'index', 'infinity', 'insert', 'into', 'is', 'keyspace', 'limit',
+ 'columnfamily', 'create', 'commit', 'delete', 'desc', 'describe', 'drop', 'end', 'entries', 'execute', 'from',
+ 'full', 'grant', 'if', 'in', 'index', 'infinity', 'insert', 'into', 'is', 'keyspace', 'let', 'limit',
'materialized', 'modify', 'nan', 'norecursive', 'not', 'null', 'of', 'on', 'or', 'order',
- 'primary', 'rename', 'revoke', 'schema', 'select', 'set', 'table', 'to', 'token', 'truncate',
+ 'primary', 'rename', 'revoke', 'schema', 'select', 'set', 'table', 'then', 'to', 'token', 'transaction', 'truncate',
'unlogged', 'update', 'use', 'using', 'view', 'where', 'with'}
"""
Set of reserved keywords in CQL.
@@ -147,7 +147,7 @@ class CqlParsingRuleSet(pylexotron.ParsingRuleSet):
else:
output.append(stmt)
if len(stmt) > 2:
- if stmt[-3][1].upper() == 'APPLY':
+ if stmt[-3][1].upper() == 'APPLY' or stmt[0][1].upper() == 'COMMIT' or (stmt[0][1].upper() == 'END' and stmt[1][1].upper() == 'IF'):
in_batch = False
elif stmt[0][1].upper() == 'BEGIN':
in_batch = True
diff --git a/simulator.sh b/simulator.sh
new file mode 100755
index 0000000000..516405e974
--- /dev/null
+++ b/simulator.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#ant jar simulator-jars
+
+DIR=`pwd`
+JVM_OPTS="$JVM_OPTS -Dcassandra.config=file://$DIR/test/conf/cassandra.yaml"
+JVM_OPTS="$JVM_OPTS -Dlogback.configurationFile=file://$DIR/test/conf/logback-simulator.xml"
+JVM_OPTS="$JVM_OPTS -Dcassandra.logdir=$DIR/build/test/logs"
+#JVM_OPTS="$JVM_OPTS -Djava.library.path=$DIR/lib/sigar-bin"
+JVM_OPTS="$JVM_OPTS -Dlegacy-sstable-root=$DIR/test/data/legacy-sstables"
+JVM_OPTS="$JVM_OPTS -Dinvalid-legacy-sstable-root=$DIR/test/data/invalid-legacy-sstables"
+JVM_OPTS="$JVM_OPTS -Dcassandra.ring_delay_ms=1000"
+JVM_OPTS="$JVM_OPTS -Dcassandra.skip_sync=true"
+JVM_OPTS="$JVM_OPTS -ea"
+JVM_OPTS="$JVM_OPTS -XX:MaxMetaspaceSize=1G"
+JVM_OPTS="$JVM_OPTS -XX:SoftRefLRUPolicyMSPerMB=0"
+JVM_OPTS="$JVM_OPTS -Dcassandra.strict.runtime.checks=true"
+JVM_OPTS="$JVM_OPTS -javaagent:$DIR/build/test/lib/jars/simulator-asm.jar"
+JVM_OPTS="$JVM_OPTS -Xbootclasspath/a:$DIR/build/test/lib/jars/simulator-bootstrap.jar"
+JVM_OPTS="$JVM_OPTS -XX:ActiveProcessorCount=4"
+JVM_OPTS="$JVM_OPTS -XX:-TieredCompilation"
+JVM_OPTS="$JVM_OPTS -XX:Tier4CompileThreshold=1000"
+JVM_OPTS="$JVM_OPTS -XX:ReservedCodeCacheSize=256M"
+JVM_OPTS="$JVM_OPTS -Xmx8G"
+JVM_OPTS="$JVM_OPTS -Dcassandra.test.simulator.determinismcheck=strict"
+JVM_OPTS="$JVM_OPTS -Dcassandra.debugrefcount=false"
+JVM_OPTS="$JVM_OPTS -Dcassandra.skip_sync=true"
+JVM_OPTS="$JVM_OPTS -Dcassandra.tolerate_sstable_size=true"
+JVM_OPTS="$JVM_OPTS -Dcassandra.test.simulator.debug=true"
+JVM_OPTS="$JVM_OPTS -Dcassandra.test.simulator.determinismcheck=strict"
+echo $JVM_OPTS
+
+CLASSPATH="$DIR"/build/test/classes
+for dir in "$DIR"/build/classes/*; do
+ CLASSPATH="$CLASSPATH:$dir"
+done
+
+for jar in "$DIR"/lib/*.jar; do
+ CLASSPATH="$CLASSPATH:$jar"
+done
+for jar in "$DIR"/build/*.jar; do
+ if [[ $jar != *"logback-classic"* ]]; then
+ CLASSPATH="$CLASSPATH:$jar"
+ fi
+done
+for jar in "$DIR"/build/lib/jars/*.jar; do
+ if [[ $jar != *"logback-classic"* ]]; then
+ CLASSPATH="$CLASSPATH:$jar"
+ fi
+done
+for jar in "$DIR"/build/test/lib/jars/*.jar; do
+ if [[ $jar != *"logback-classic"* ]]; then
+ CLASSPATH="$CLASSPATH:$jar"
+ fi
+done
+
+CLASS="org.apache.cassandra.simulator.paxos.AccordSimulationRunner"
+OPTS="run -n 3..6 -t 1000 --cluster-action-limit -1 -c 2 -s 30"
+
+echo "java -cp <...> $CLASS $OPTS $@"
+
+while true
+do
+ echo ""
+ java -cp $CLASSPATH $JVM_OPTS $CLASS $OPTS $@
+ status=$?
+ if [ $status -ne 0 ] ; then
+ exit $status
+ fi
+
+done
diff --git a/src/antlr/Cql.g b/src/antlr/Cql.g
index fe068f4b5a..8cf53980be 100644
--- a/src/antlr/Cql.g
+++ b/src/antlr/Cql.g
@@ -46,6 +46,7 @@ import Parser,Lexer;
import org.apache.cassandra.cql3.statements.*;
import org.apache.cassandra.cql3.statements.schema.*;
import org.apache.cassandra.cql3.terms.*;
+ import org.apache.cassandra.cql3.transactions.*;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.exceptions.SyntaxException;
diff --git a/src/antlr/Lexer.g b/src/antlr/Lexer.g
index b192021fa3..b3ae1aba49 100644
--- a/src/antlr/Lexer.g
+++ b/src/antlr/Lexer.g
@@ -60,6 +60,7 @@ lexer grammar Lexer;
// pylib/cqlshlib/cqlhandling.py::cql_keywords_reserved.
// When adding a new unreserved keyword, add entry to unreserved keywords in Parser.g.
K_SELECT: S E L E C T;
+K_LET: L E T;
K_FROM: F R O M;
K_AS: A S;
K_WHERE: W H E R E;
@@ -83,8 +84,10 @@ K_BEGIN: B E G I N;
K_UNLOGGED: U N L O G G E D;
K_BATCH: B A T C H;
K_APPLY: A P P L Y;
+K_COMMIT: C O M M I T;
K_TRUNCATE: T R U N C A T E;
K_DELETE: D E L E T E;
+K_TRANSACTION: T R A N S A C T I O N;
K_IN: I N;
K_CREATE: C R E A T E;
K_SCHEMA: S C H E M A;
@@ -123,6 +126,8 @@ K_DESC: D E S C;
K_ALLOW: A L L O W;
K_FILTERING: F I L T E R I N G;
K_IF: I F;
+K_THEN: T H E N;
+K_END: E N D;
K_IS: I S;
K_CONTAINS: C O N T A I N S;
K_BETWEEN: B E T W E E N;
diff --git a/src/antlr/Parser.g b/src/antlr/Parser.g
index c91dfe60d9..8ac85ec1f4 100644
--- a/src/antlr/Parser.g
+++ b/src/antlr/Parser.g
@@ -27,6 +27,13 @@ options {
private final List listeners = new ArrayList();
protected final List bindVariables = new ArrayList();
+ // enables parsing txn specific syntax when true
+ protected boolean isParsingTxn = false;
+ // tracks whether a txn has conditional updates
+ protected boolean isTxnConditional = false;
+
+ protected List references;
+
public static final Set reservedTypeNames = new HashSet()
{{
add("byte");
@@ -59,6 +66,19 @@ options {
return marker;
}
+ public RowDataReference.Raw newRowDataReference(Selectable.RawIdentifier tuple, Selectable.Raw selectable)
+ {
+ if (!isParsingTxn)
+ throw new SyntaxException("Cannot create a row data reference unless parsing a transaction");
+
+ if (references == null)
+ references = new ArrayList<>();
+
+ RowDataReference.Raw reference = RowDataReference.Raw.fromSelectable(tuple, selectable);
+ references.add(reference);
+ return reference;
+ }
+
public void addErrorListener(ErrorListener listener)
{
this.listeners.add(listener);
@@ -122,14 +142,24 @@ options {
return res;
}
- public void addRawUpdate(List> operations, ColumnIdentifier key, Operation.RawUpdate update)
+ public void addRawUpdate(UpdateStatement.OperationCollector collector, ColumnIdentifier key, Operation.RawUpdate update)
{
- for (Pair p : operations)
- {
- if (p.left.equals(key) && !p.right.isCompatibleWith(update))
- addRecognitionError("Multiple incompatible setting of column " + key);
- }
- operations.add(Pair.create(key, update));
+ if (collector.conflictsWithExistingUpdate(key, update))
+ addRecognitionError("Multiple incompatible setting of column " + key);
+ if (collector.conflictsWithExistingSubstitution(key))
+ addRecognitionError("Normal and reference operations for " + key);
+
+ collector.addRawUpdate(key, update);
+ }
+
+ public void addRawReferenceOperation(UpdateStatement.OperationCollector collector, ColumnIdentifier key, ReferenceOperation.Raw update)
+ {
+ if (collector.conflictsWithExistingUpdate(key))
+ addRecognitionError("Multiple incompatible setting of column " + key);
+ if (collector.conflictsWithExistingSubstitution(key))
+ addRecognitionError("Normal and reference operations for " + key);
+
+ collector.addRawReferenceOperation(key, update);
}
public Set filterPermissions(Set permissions, IResource resource)
@@ -237,6 +267,8 @@ cqlStatement returns [CQLStatement.Raw stmt]
| st43=dropIdentityStatement { $stmt = st43; }
| st44=listSuperUsersStatement { $stmt = st44; }
| st45=copyTableStatement { $stmt = st45; }
+ | st46=batchTxnStatement { $stmt = st46; }
+ | st47=letStatement { $stmt = st47; }
;
/*
@@ -276,11 +308,39 @@ selectStatement returns [SelectStatement.RawStatement expr]
groups,
$sclause.isDistinct,
allowFiltering,
- isJson);
+ isJson,
+ null);
WhereClause where = wclause == null ? WhereClause.empty() : wclause.build();
$expr = new SelectStatement.RawStatement(cf, params, $sclause.selectors, where, limit, perPartitionLimit);
}
;
+
+/**
+ * ex. LET x = (SELECT * FROM