├── .gitignore ├── docs ├── Hands-on With Apache Cassandra ACID Transactions.pdf ├── README.md ├── quickstart.md ├── use-cases.md └── cassandra_transactional_guide.md ├── examples ├── banking │ ├── sample_data.cql │ ├── verify_transfer.cql │ ├── schemas.cql │ ├── transfer.cql │ ├── setup.sh │ └── README.md ├── inventory │ ├── sample_data.cql │ ├── schemas.cql │ ├── transaction.cql │ ├── setup.sh │ └── README.md ├── user-management │ ├── sample_data.cql │ ├── schemas.cql │ ├── transaction.cql │ ├── setup.sh │ └── README.md └── README.md ├── docker ├── build │ ├── build.sh │ ├── Dockerfile │ └── README.md ├── docker-compose.yml ├── test-transactions.sh └── README.md ├── easy-cass-lab └── README.md ├── CONTRIBUTING.md ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | # Common files 2 | *.DS_Store 3 | *.key 4 | *.log -------------------------------------------------------------------------------- /docs/Hands-on With Apache Cassandra ACID Transactions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmcfadin/awesome-accord/HEAD/docs/Hands-on With Apache Cassandra ACID Transactions.pdf -------------------------------------------------------------------------------- /examples/banking/sample_data.cql: -------------------------------------------------------------------------------- 1 | -- Insert initial account data 2 | INSERT INTO banking.accounts(account_holder, account_balance) VALUES ('bob', 100); 3 | INSERT INTO banking.accounts(account_holder, account_balance) VALUES ('alice', 100); -------------------------------------------------------------------------------- /examples/inventory/sample_data.cql: -------------------------------------------------------------------------------- 1 | -- Insert initial product inventory 2 | INSERT INTO inventory.products(item, inventory_count) 3 | VALUES ('PlayStation 5', 100); 4 | 5 | INSERT INTO inventory.products(item, inventory_count) 6 | VALUES ('Xbox Series X', 75); 7 | 8 | INSERT INTO inventory.products(item, inventory_count) 9 | VALUES ('Nintendo Switch', 150); -------------------------------------------------------------------------------- /examples/banking/verify_transfer.cql: -------------------------------------------------------------------------------- 1 | -- Verify account balances 2 | SELECT account_id, balance, currency 3 | FROM banking.accounts 4 | WHERE account_id IN ('ACC001', 'ACC002'); 5 | 6 | -- Show recent transactions 7 | SELECT account_id, transaction_type, amount, status 8 | FROM banking.transactions 9 | WHERE account_id IN ('ACC001', 'ACC002') 10 | ORDER BY timestamp DESC 11 | LIMIT 10; -------------------------------------------------------------------------------- /examples/banking/schemas.cql: -------------------------------------------------------------------------------- 1 | -- Create keyspace 2 | CREATE KEYSPACE IF NOT EXISTS banking 3 | WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}; 4 | 5 | -- Create accounts table with transactional support 6 | CREATE TABLE IF NOT EXISTS banking.accounts ( 7 | account_holder text, 8 | account_balance decimal, 9 | PRIMARY KEY (account_holder) 10 | ) WITH transactional_mode = 'full'; -------------------------------------------------------------------------------- /examples/user-management/sample_data.cql: -------------------------------------------------------------------------------- 1 | -- Insert first user 2 | INSERT INTO users.user(user_id, email, country, city) 3 | VALUES (a5a13946-4366-11ed-b878-0242ac120003, 'jane@example.com', 'UK', 'London'); 4 | 5 | INSERT INTO users.user_by_email(email, user_id) 6 | VALUES ('jane@example.com', a5a13946-4366-11ed-b878-0242ac120003); 7 | 8 | INSERT INTO users.user_by_location(country, city, user_id) 9 | VALUES ('UK', 'London', a5a13946-4366-11ed-b878-0242ac120003); -------------------------------------------------------------------------------- /docker/build/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e # Exit on error 4 | 5 | # Check for cassandra directory 6 | if [ ! -d "cassandra" ]; then 7 | echo "Error: cassandra directory not found" 8 | echo "Please checkout and build the Cassandra Accord branch first" 9 | exit 1 10 | fi 11 | 12 | # Build Docker image 13 | echo "Building Docker image..." 14 | docker build -t cassandra-accord . 15 | 16 | echo "Build completed successfully!" 17 | echo "Run: docker run -d --name cassandra-accord -p 9042:9042 cassandra-accord" -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | cassandra: 3 | image: pmcfadin/cassandra-accord 4 | environment: 5 | - MAX_HEAP_SIZE=512M 6 | - HEAP_NEWSIZE=100M 7 | - CASSANDRA_SEEDS=cassandra 8 | - CASSANDRA_CLUSTER_NAME=AccordCluster 9 | ports: 10 | - "9042:9042" 11 | volumes: 12 | - cassandra_data:/opt/cassandra/data 13 | healthcheck: 14 | test: ["CMD", "./bin/cqlsh", "-e", "describe keyspaces"] 15 | interval: 15s 16 | timeout: 10s 17 | retries: 10 18 | 19 | volumes: 20 | cassandra_data: 21 | driver: local -------------------------------------------------------------------------------- /examples/inventory/schemas.cql: -------------------------------------------------------------------------------- 1 | -- Create keyspace 2 | CREATE KEYSPACE IF NOT EXISTS inventory 3 | WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}; 4 | 5 | -- Products table with transactional support 6 | CREATE TABLE IF NOT EXISTS inventory.products ( 7 | item text, 8 | inventory_count decimal, 9 | PRIMARY KEY (item) 10 | ) WITH transactional_mode = 'full'; 11 | 12 | -- Shopping cart table with transactional support 13 | CREATE TABLE IF NOT EXISTS inventory.shopping_cart ( 14 | user_name text, 15 | item text, 16 | item_count decimal, 17 | PRIMARY KEY (user_name, item) 18 | ) WITH transactional_mode = 'full'; -------------------------------------------------------------------------------- /examples/user-management/schemas.cql: -------------------------------------------------------------------------------- 1 | -- Create keyspace 2 | CREATE KEYSPACE IF NOT EXISTS users 3 | WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}; 4 | 5 | -- Primary user table 6 | CREATE TABLE users.user ( 7 | user_id UUID, 8 | email text, 9 | country text, 10 | city text, 11 | PRIMARY KEY (user_id) 12 | ) WITH transactional_mode = 'full'; 13 | 14 | -- Email lookup table 15 | CREATE TABLE users.user_by_email ( 16 | email text, 17 | user_id UUID, 18 | PRIMARY KEY (email) 19 | ) WITH transactional_mode = 'full'; 20 | 21 | -- Location lookup table 22 | CREATE TABLE users.user_by_location ( 23 | country text, 24 | city text, 25 | user_id UUID, 26 | PRIMARY KEY ((country, city), user_id) 27 | ) WITH transactional_mode = 'full'; -------------------------------------------------------------------------------- /docker/build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17-jdk-slim 2 | 3 | # Install required packages 4 | RUN apt-get update && apt-get install -y procps python3 python3-pip 5 | 6 | # Install Python Cassandra driver 7 | RUN pip3 install --no-cache-dir cassandra-driver 8 | 9 | # Copy the Cassandra build into the container 10 | COPY cassandra /opt/cassandra 11 | 12 | # Set environment variables 13 | ENV MAX_HEAP_SIZE=512M 14 | ENV HEAP_NEWSIZE=100M 15 | 16 | # Create a non-root user and set permissions 17 | RUN useradd -ms /bin/bash cassandra-user 18 | RUN chown -R cassandra-user:cassandra-user /opt/cassandra 19 | 20 | # Switch to non-root user 21 | USER cassandra-user 22 | 23 | # Set the working directory 24 | WORKDIR /opt/cassandra 25 | 26 | # Expose ports 27 | EXPOSE 7000 7001 7199 9042 9160 28 | 29 | # Run Cassandra 30 | ENTRYPOINT ["./bin/cassandra", "-f"] 31 | -------------------------------------------------------------------------------- /examples/inventory/transaction.cql: -------------------------------------------------------------------------------- 1 | BEGIN TRANSACTION 2 | -- Find out how many PlayStations are left 3 | LET inventory = (SELECT inventory_count FROM inventory.products WHERE item='PlayStation 5'); 4 | 5 | -- Return the inventory count before deducting 6 | SELECT item, inventory_count FROM inventory.products WHERE item='PlayStation 5'; 7 | 8 | -- Take a PlayStation out of inventory and put in users shopping cart 9 | IF inventory.inventory_count > 0 THEN 10 | UPDATE inventory.products SET inventory_count -= 1 WHERE item='PlayStation 5'; 11 | INSERT INTO inventory.shopping_cart(user_name, item, item_count) 12 | VALUES ('patrick', 'PlayStation 5', 1); 13 | END IF 14 | COMMIT TRANSACTION; 15 | 16 | -- Verify the results 17 | SELECT * FROM inventory.products WHERE item='PlayStation 5'; 18 | SELECT * FROM inventory.shopping_cart WHERE user_name='patrick'; -------------------------------------------------------------------------------- /examples/banking/transfer.cql: -------------------------------------------------------------------------------- 1 | BEGIN TRANSACTION 2 | -- Get the balance from Alices account and store as a Tuple 3 | LET fromBalance = (SELECT account_balance FROM banking.accounts WHERE account_holder='alice'); 4 | 5 | -- Return the balance before update after transaction complete 6 | SELECT account_balance FROM banking.accounts WHERE account_holder='alice'; 7 | 8 | -- If Alices account balance is greater than $20, move $20 to Bob 9 | IF fromBalance.account_balance >= 20 THEN 10 | UPDATE banking.accounts SET account_balance -= 20 WHERE account_holder='alice'; 11 | UPDATE banking.accounts SET account_balance +=20 WHERE account_holder='bob'; 12 | END IF 13 | COMMIT TRANSACTION; 14 | 15 | -- Show the money was moved 16 | SELECT account_balance FROM banking.accounts WHERE account_holder='alice'; 17 | SELECT account_balance FROM banking.accounts WHERE account_holder='bob'; -------------------------------------------------------------------------------- /examples/user-management/transaction.cql: -------------------------------------------------------------------------------- 1 | -- Add a new user with duplicate email check 2 | BEGIN TRANSACTION 3 | -- Find any existing users with same email 4 | LET existCheck = (SELECT user_id FROM users.user_by_email WHERE email='patrick@datastax.com'); 5 | 6 | -- If email isn't in use, then add the new user 7 | IF existCheck IS NULL THEN 8 | INSERT INTO users.user(user_id, email, country, city) 9 | VALUES (94813846-4366-11ed-b878-0242ac120002, 'patrick@datastax.com', 'US', 'Windsor'); 10 | 11 | INSERT INTO users.user_by_email(email, user_id) 12 | VALUES ('patrick@datastax.com', 94813846-4366-11ed-b878-0242ac120002); 13 | 14 | INSERT INTO users.user_by_location(country, city, user_id) 15 | VALUES ('US', 'Windsor', 94813846-4366-11ed-b878-0242ac120002); 16 | END IF 17 | COMMIT TRANSACTION; 18 | 19 | -- Query user by email 20 | SELECT * FROM users.user_by_email WHERE email='patrick@datastax.com'; 21 | 22 | -- Find users in a specific location 23 | SELECT * FROM users.user_by_location WHERE country='US' AND city='Windsor'; -------------------------------------------------------------------------------- /examples/banking/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Setting up banking transaction examples..." 4 | 5 | # Check if Cassandra is running 6 | if ! docker ps | grep -q cassandra-accord; then 7 | echo "Starting Cassandra container..." 8 | docker run -d --name cassandra-accord -p 9042:9042 pmcfadin/cassandra-accord 9 | 10 | # Wait for Cassandra to be ready 11 | echo "Waiting for Cassandra to start..." 12 | while ! docker exec cassandra-accord ./bin/cqlsh -e "describe keyspaces" > /dev/null 2>&1; do 13 | sleep 2 14 | done 15 | fi 16 | 17 | # Create schema 18 | echo "Creating schema..." 19 | docker exec -i cassandra-accord ./bin/cqlsh < schemas.cql 20 | 21 | # Load sample data 22 | echo "Loading sample data..." 23 | docker exec -i cassandra-accord ./bin/cqlsh < sample_data.cql 24 | 25 | echo "Setup complete! Running verification..." 26 | 27 | # Verify setup 28 | docker exec -i cassandra-accord ./bin/cqlsh -e " 29 | SELECT account_holder, account_balance 30 | FROM banking.accounts;" 31 | 32 | echo "" 33 | echo "Setup complete! You can now run transfers using:" 34 | echo "docker exec -i cassandra-accord ./bin/cqlsh < transfer.cql" -------------------------------------------------------------------------------- /examples/user-management/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Setting up user management transaction examples..." 4 | 5 | # Check if Cassandra is running 6 | if ! docker ps | grep -q cassandra-accord; then 7 | echo "Starting Cassandra container..." 8 | docker run -d --name cassandra-accord -p 9042:9042 pmcfadin/cassandra-accord 9 | 10 | # Wait for Cassandra to be ready 11 | echo "Waiting for Cassandra to start..." 12 | while ! docker exec cassandra-accord ./bin/cqlsh -e "describe keyspaces" > /dev/null 2>&1; do 13 | sleep 2 14 | done 15 | fi 16 | 17 | # Create schema 18 | echo "Creating schema..." 19 | docker exec -i cassandra-accord ./bin/cqlsh < schemas.cql 20 | 21 | # Load sample data 22 | echo "Loading sample data..." 23 | docker exec -i cassandra-accord ./bin/cqlsh < sample_data.cql 24 | 25 | echo "Setup complete! Running verification..." 26 | 27 | # Verify setup 28 | docker exec -i cassandra-accord ./bin/cqlsh -e "SELECT email, country, city FROM users.user;" 29 | 30 | echo "" 31 | echo "Setup complete! You can now run user management transactions using:" 32 | echo "docker exec -i cassandra-accord ./bin/cqlsh < transaction.cql" -------------------------------------------------------------------------------- /examples/inventory/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Setting up inventory transaction examples..." 4 | 5 | # Check if Cassandra is running 6 | if ! docker ps | grep -q cassandra-accord; then 7 | echo "Starting Cassandra container..." 8 | docker run -d --name cassandra-accord -p 9042:9042 pmcfadin/cassandra-accord 9 | 10 | # Wait for Cassandra to be ready 11 | echo "Waiting for Cassandra to start..." 12 | while ! docker exec cassandra-accord ./bin/cqlsh -e "describe keyspaces" > /dev/null 2>&1; do 13 | sleep 2 14 | done 15 | fi 16 | 17 | # Create schema 18 | echo "Creating schema..." 19 | docker exec -i cassandra-accord ./bin/cqlsh < schemas.cql 20 | 21 | # Load sample data 22 | echo "Loading sample data..." 23 | docker exec -i cassandra-accord ./bin/cqlsh < sample_data.cql 24 | 25 | echo "Setup complete! Running verification..." 26 | 27 | # Verify setup 28 | docker exec -i cassandra-accord ./bin/cqlsh -e " 29 | SELECT item, inventory_count 30 | FROM inventory.products;" 31 | 32 | echo "" 33 | echo "Setup complete! You can now run inventory transactions using:" 34 | echo "docker exec -i cassandra-accord ./bin/cqlsh < transaction.cql" -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Accord Transaction Examples 2 | 3 | This directory contains practical, production-ready examples of using Accord transactions in Apache Cassandra. Each example includes complete schema definitions, transaction implementations, and usage instructions. 4 | 5 | ## Directory Structure 6 | 7 | ``` 8 | examples/ 9 | ├── banking/ # Financial transaction examples 10 | ├── inventory/ # Inventory management examples 11 | └── user-management/ # User registration and management 12 | ``` 13 | 14 | ## Example Categories 15 | 16 | ### Banking Examples 17 | - Account transfers with overdraft protection 18 | - Multi-currency transactions 19 | - Account creation with constraints 20 | 21 | ### Inventory Management 22 | - Product inventory tracking 23 | - Shopping cart implementation 24 | - Reservation system 25 | 26 | ### User Management 27 | - User registration with unique constraints 28 | - Profile updates across multiple tables 29 | - Session management 30 | 31 | ## Running the Examples 32 | 33 | 1. Start Accord-enabled Cassandra: 34 | ```bash 35 | docker pull pmcfadin/cassandra-accord 36 | docker run -d --name cassandra-accord -p 9042:9042 pmcfadin/cassandra-accord 37 | ``` 38 | 39 | 2. Navigate to an example directory: 40 | ```bash 41 | cd examples/banking 42 | ``` 43 | 44 | 3. Run the setup script: 45 | ```bash 46 | ./setup.sh 47 | ``` 48 | 49 | 4. Follow the example-specific README for detailed instructions. 50 | 51 | ## Contributing 52 | 53 | Give us anyfeedback you have in [Github Discussions](https://github.com/pmcfadin/awesome-accord/) 54 | Want to add an example? See our [contribution guidelines](../CONTRIBUTING.md). 55 | 56 | ## Getting Help 57 | 58 | - Check the [documentation](../docs/) 59 | - Join our [Discord](https://discord.gg/GrRCajJqmQ) 60 | -------------------------------------------------------------------------------- /docker/test-transactions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Test script for Accord transactions in Cassandra 4 | # This script runs a series of tests to verify transaction functionality 5 | 6 | echo "Testing Accord Transactions..." 7 | 8 | # Wait for Cassandra to be ready 9 | while ! docker exec cassandra-accord ./bin/cqlsh -e "describe keyspaces" > /dev/null 2>&1; do 10 | echo "⏳ Waiting for Cassandra to start..." 11 | sleep 5 12 | done 13 | 14 | echo "✅ Cassandra is ready!" 15 | 16 | # Create test keyspace and table 17 | docker exec cassandra-accord ./bin/cqlsh << EOF 18 | CREATE KEYSPACE IF NOT EXISTS demo 19 | WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}; 20 | 21 | CREATE TABLE IF NOT EXISTS demo.products ( 22 | item text, 23 | inventory_count decimal, 24 | PRIMARY KEY (item) 25 | ) WITH transactional_mode = 'full' 26 | EOF 27 | 28 | echo "Created test table" 29 | 30 | # Insert test data 31 | docker exec cassandra-accord ./bin/cqlsh << EOF 32 | INSERT INTO demo.products(item, inventory_count) 33 | VALUES ('test_item', 100) 34 | EOF 35 | 36 | echo "Inserted test data" 37 | 38 | # Run test transaction 39 | docker exec cassandra-accord ./bin/cqlsh << EOF 40 | BEGIN TRANSACTION 41 | UPDATE demo.products 42 | SET inventory_count -= 1 43 | WHERE item='test_item'; 44 | COMMIT TRANSACTION 45 | EOF 46 | 47 | echo "Executed test transaction" 48 | 49 | # Verify result 50 | RESULT=$(docker exec cassandra-accord ./bin/cqlsh -e "SELECT inventory_count FROM demo.products WHERE item='test_item'" | grep -A 2 inventory_count | tail -n 1 | tr -d ' ') 51 | 52 | echo "Result: $RESULT" 53 | 54 | if [ "$RESULT" = "99" ]; then 55 | echo "✅ Transaction test passed!" 56 | else 57 | echo "❌ Transaction test failed!" 58 | echo "Expected: 99" 59 | echo "Got: $RESULT" 60 | exit 1 61 | fi -------------------------------------------------------------------------------- /examples/inventory/README.md: -------------------------------------------------------------------------------- 1 | # Cassandra ACID Transactions: Inventory Management Example 2 | 3 | This example demonstrates how to implement a robust inventory management system using Apache Cassandra's ACID transactions. The example showcases how to handle concurrent inventory updates while maintaining data consistency. 4 | 5 | ## Overview 6 | 7 | The example implements two main tables: 8 | - `products`: Stores product information and inventory counts 9 | - `shopping_cart`: Tracks items added to user shopping carts 10 | 11 | Key features demonstrated: 12 | - Atomic inventory updates 13 | - Race condition prevention 14 | - Shopping cart management 15 | - Transactional consistency across tables 16 | 17 | ## Prerequisites 18 | 19 | - Docker installed on your system 20 | - Basic understanding of CQL (Cassandra Query Language) 21 | 22 | ## Quick Start 23 | 24 | 1. Run the setup script: 25 | ```bash 26 | ./setup.sh 27 | ``` 28 | 29 | This will: 30 | - Start a Cassandra container with Accord transactions enabled 31 | - Create the necessary schema 32 | - Load sample data 33 | - Verify the setup 34 | 35 | 2. Try the example transaction: 36 | ```bash 37 | docker exec -i cassandra-accord ./bin/cqlsh < transaction.cql 38 | ``` 39 | 40 | ## Files Included 41 | 42 | - `schemas.cql`: Table definitions 43 | - `sample_data.cql`: Initial data load 44 | - `transaction.cql`: Example transaction 45 | - `setup.sh`: Setup script 46 | 47 | ## Join Our Community! 48 | 49 | Have questions or want to learn more about Cassandra transactions? 50 | 51 | Check out the [Github Discussions](https://github.com/pmcfadin/awesome-accord/) in the repository or... 52 | 53 | Join our Discord community: 54 | https://discord.gg/GrRCajJqmQ 55 | 56 | ## Next Steps 57 | 58 | - Explore other transaction examples in this repository 59 | - Try modifying the inventory counts and observe ACID properties 60 | - Implement your own transactional workflows -------------------------------------------------------------------------------- /docker/build/README.md: -------------------------------------------------------------------------------- 1 | # Cassandra Accord Docker 2 | 3 | Run Apache Cassandra with ACID transactions using the Accord protocol. This Docker setup provides a ready-to-use environment for development and testing. 4 | 5 | ## Prerequisites 6 | - Docker 7 | - Git 8 | - Ant (for building Cassandra) 9 | 10 | ## Building 11 | 12 | First, build Cassandra with Accord: 13 | ```bash 14 | # Clone Cassandra 15 | git clone https://github.com/apache/cassandra.git 16 | cd cassandra 17 | 18 | # Checkout Accord branch 19 | git checkout cep-15-accord 20 | 21 | # Build Cassandra 22 | ant clean 23 | ant 24 | cd .. 25 | ``` 26 | 27 | Then build the Docker image: 28 | ```bash 29 | chmod +x build.sh 30 | ./build.sh 31 | ``` 32 | 33 | ## Running 34 | 35 | ```bash 36 | # Start a container 37 | docker run -d --name cassandra-accord -p 9042:9042 cassandra-accord 38 | 39 | # Connect with cqlsh 40 | docker exec -it cassandra-accord ./bin/cqlsh 41 | ``` 42 | 43 | ## Quick Example 44 | 45 | ```sql 46 | -- Create a table with transactions enabled 47 | CREATE TABLE demo.accounts ( 48 | account_holder text, 49 | balance decimal, 50 | PRIMARY KEY (account_holder) 51 | ) WITH transactional_mode = 'full'; 52 | 53 | -- Use transactions 54 | BEGIN TRANSACTION 55 | UPDATE demo.accounts SET balance -= 100 WHERE account_holder = 'alice'; 56 | UPDATE demo.accounts SET balance += 100 WHERE account_holder = 'bob'; 57 | COMMIT TRANSACTION; 58 | ``` 59 | 60 | ## Configuration 61 | 62 | Environment variables: 63 | - `MAX_HEAP_SIZE` (default: 512M) 64 | - `HEAP_NEWSIZE` (default: 100M) 65 | 66 | Example with custom config: 67 | ```bash 68 | docker run -d \ 69 | -e MAX_HEAP_SIZE=1G \ 70 | -e HEAP_NEWSIZE=200M \ 71 | -p 9042:9042 \ 72 | cassandra-accord 73 | ``` 74 | 75 | ## Community 76 | 77 | Join our Discord for support and discussion: [https://discord.gg/GrRCajJqmQ](https://discord.gg/GrRCajJqmQ) 78 | 79 | ## License 80 | 81 | Apache License 2.0 -------------------------------------------------------------------------------- /examples/user-management/README.md: -------------------------------------------------------------------------------- 1 | # User Management with Cassandra ACID Transactions 2 | 3 | This example demonstrates how to implement a robust user management system using Cassandra's ACID transaction capabilities. The example showcases managing user data across multiple tables while maintaining consistency and preventing duplicate email registrations. 4 | 5 | ## Overview 6 | 7 | The example implements: 8 | - Primary user storage with UUID-based lookups 9 | - Email-based user lookups 10 | - Location-based user lookups 11 | - Atomic updates across all tables 12 | - Duplicate email prevention 13 | 14 | ## Prerequisites 15 | 16 | - Docker installed on your system 17 | - Basic understanding of CQL (Cassandra Query Language) 18 | 19 | ## Quick Start 20 | 21 | 1. Run the setup script: 22 | ```bash 23 | ./setup.sh 24 | ``` 25 | 26 | This will: 27 | - Start a Cassandra container with Accord transactions enabled 28 | - Create the necessary schema 29 | - Load sample data 30 | - Verify the setup 31 | 32 | ## Schema Design 33 | 34 | The example uses three tables: 35 | - `users.user`: Primary user storage 36 | - `users.user_by_email`: Email lookup index 37 | - `users.user_by_location`: Location-based lookup index 38 | 39 | ## Files Included 40 | 41 | - `setup.sh`: Setup script for running the example 42 | - `schemas.cql`: Table definitions 43 | - `sample_data.cql`: Sample user data 44 | - `queries.cql`: Example transactional queries 45 | 46 | ## Try It Out 47 | 48 | After running setup.sh, you can: 49 | 1. Query users by ID 50 | 2. Look up users by email 51 | 3. Find users by location 52 | 4. Add new users atomically 53 | 54 | Example query: 55 | ```sql 56 | SELECT * FROM users.user_by_email WHERE email='patrick@datastax.com'; 57 | ``` 58 | 59 | ## Join Our Community 60 | 61 | Have questions or want to learn more about Cassandra transactions? 62 | Check out the [Github Discussions](https://github.com/pmcfadin/awesome-accord/) in the repository or... 63 | 64 | Join our Discord community: 65 | https://discord.gg/GrRCajJqmQ 66 | -------------------------------------------------------------------------------- /easy-cass-lab/README.md: -------------------------------------------------------------------------------- 1 | # Creating a Cluster in AWS using easy-cass-lab 2 | 3 | This guide provides step-by-step instructions for creating a Cassandra cluster on AWS using the easy-cass-lab tool. 4 | 5 | ## Prerequisites 6 | 7 | Before you begin, ensure that you have either built or installed easy-cass-lab via homebrew. Follow the [Homebrew installation 8 | instructions](https://rustyrazorblade.com/post/2024/easy-cass-lab-homebrew/) if you haven't done so already, 9 | or build from source following the instructions in the [repo](https://github.com/rustyrazorblade/easy-cass-lab). 10 | 11 | ## QuickStart 12 | 13 | First, create a directory where you want to set up your Cassandra environment and navigate into it: 14 | ```shell 15 | mkdir accord-test 16 | cd accord-test 17 | ``` 18 | 19 | Use easy-cass-lab to provision instances on AWS: 20 | 21 | Initialize the cluster with three coordinator nodes and one seed node: 22 | ```shell 23 | easy-cass-lab init -c 3 -s 1 accord-test 24 | ``` 25 | 26 | Start the provisioning process: 27 | ```shell 28 | easy-cass-lab up 29 | ``` 30 | 31 | This will set up the necessary AWS infrastructure for your Cassandra cluster. 32 | 33 | To ensure you're using a specific version with the Accord build, execute: 34 | 35 | ```shell 36 | easy-cass-lab use accord 37 | ``` 38 | 39 | Then, start the cluster: 40 | 41 | ```shell 42 | easy-cass-lab start 43 | ``` 44 | 45 | Your Cassandra cluster is now up and running on AWS. You can begin interacting with it for testing or development purposes. 46 | 47 | To load the cluster's state into your shell's environment, run the following: 48 | 49 | ```shell 50 | source env.sh 51 | ``` 52 | 53 | Either of the following two commands can SSH to the first node: 54 | 55 | ```shell 56 | ssh cassandra0 57 | c0 58 | ``` 59 | 60 | You can also SSH to the stress0 node: 61 | 62 | ```shell 63 | ssh stress0 64 | s0 65 | ``` 66 | 67 | You can upload files to the stress node by doing the following: 68 | 69 | ```shell 70 | scp path/to/file stress0: 71 | ``` 72 | 73 | 74 | For further customization or troubleshooting, refer to 75 | the [easy-cass-lab documentation](https://github.com/rustyrazorblade/easy-cass-lab) 76 | and explore additional configurations as needed. 77 | 78 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Accord Transaction Documentation 2 | 3 | Welcome to the Accord transaction documentation! Here you'll find resources and guides for implementing ACID transactions in Apache Cassandra. 4 | 5 | ## Table of Contents 6 | 7 | ### Getting Started 8 | - [Quick Start Guide](quickstart.md) 9 | - [Guide](cassandra_transactional_guide.md) 10 | - [Use Cases](use-cases.md) 11 | 12 | ### Deployment Options 13 | 14 | #### Docker Deployment 15 | - Single-node testing environment 16 | - Quick setup for development 17 | - Configuration guidelines 18 | - [View Docker Setup](../docker/) 19 | 20 | #### Easy-Cass-Lab 21 | - Multi-node cluster setup 22 | - Development environment configuration 23 | - Performance testing capabilities 24 | - [View Easy-Cass-Lab Setup](../easy-cass-lab/) 25 | 26 | ### Working with Transactions 27 | 28 | Learn how to implement transactions through our example use cases: 29 | 30 | #### Banking Operations 31 | - Account transfers with ACID guarantees 32 | - Balance checks and updates 33 | - Safe concurrent transactions 34 | - [View Banking Examples](../examples/banking/) 35 | 36 | #### Inventory Management 37 | - Race-free inventory tracking 38 | - Shopping cart implementation 39 | - Concurrent order processing 40 | - [View Inventory Examples](../examples/inventory/) 41 | 42 | #### User Management 43 | - Multi-table atomic operations 44 | - Safe user creation and updates 45 | - Maintaining data consistency across tables 46 | - [View User Management Examples](../examples/user-management/) 47 | 48 | ## Community Resources 49 | 50 | - Join our [Discord community](https://discord.gg/GrRCajJqmQ) for: 51 | - Real-time support 52 | - Discussion with other developers 53 | - Updates and announcements 54 | 55 | - Contributing: 56 | - Report issues via GitHub 57 | - Suggest improvements 58 | - Share your use cases 59 | 60 | ## Need Help? 61 | 62 | If you have questions or need assistance: 63 | 1. Check our example use cases 64 | 2. Review the deployment guides 65 | 3. Join our Discord community 66 | 4. Submit an issue on GitHub 67 | 68 | ## Repository Structure 69 | ``` 70 | / 71 | ├── docker/ # Docker setup files 72 | ├── easy-cass-lab/ # Multi-node cluster tools 73 | ├── examples/ # Implementation examples 74 | │ ├── banking/ # Financial transactions 75 | │ ├── inventory/ # Stock management 76 | │ └── user-management/ # User operations 77 | ├── docs/ # Documentation 78 | └── scripts/ # Utility scripts 79 | ``` -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Awesome Accord 2 | 3 | Thank you for your interest in contributing to Awesome Accord! This guide explains how to get involved and contribute to the project. 4 | 5 | ## Getting Started 6 | 7 | 1. Star the repository to help increase its visibility 8 | 2. Fork the repository to your GitHub account 9 | 3. Clone your fork locally 10 | 4. Create a new branch for your contribution 11 | 12 | ## Ways to Contribute 13 | 14 | ### Documentation 15 | - Improve existing documentation 16 | - Add new guides or tutorials 17 | - Fix typos or clarify explanations 18 | - Add additional use case examples 19 | - Translate documentation to other languages 20 | 21 | ### Code Examples 22 | - Add new transaction examples 23 | - Improve existing examples 24 | - Add comments and explanations 25 | - Create new use cases 26 | - Optimize existing implementations 27 | 28 | ### Deployment Scenarios 29 | - Add new deployment options 30 | - Improve existing deployment scripts 31 | - Document deployment best practices 32 | - Create new environment setup guides 33 | - Share configuration templates 34 | 35 | ## Contribution Process 36 | 37 | 1. Create a new branch for your work: 38 | ```bash 39 | git checkout -b feature/your-feature-name 40 | ``` 41 | 42 | 2. Make your changes and commit them: 43 | ```bash 44 | git add . 45 | git commit -m "Description of your changes" 46 | ``` 47 | 48 | 3. Push to your fork: 49 | ```bash 50 | git push origin feature/your-feature-name 51 | ``` 52 | 53 | 4. Create a Pull Request from your fork to our main repository 54 | 55 | ## Pull Request Guidelines 56 | 57 | - Provide a clear description of your changes 58 | - Reference any relevant issues 59 | - Include example code where applicable 60 | - Ensure documentation is updated if needed 61 | - Follow existing code style and formatting 62 | 63 | ## Example Contributions 64 | 65 | Here are some specific areas where we welcome contributions: 66 | 67 | ### Documentation 68 | - Additional transaction patterns 69 | - Performance optimization guides 70 | - Troubleshooting guides 71 | - Migration guides from other databases 72 | 73 | ### Code Examples 74 | - E-commerce scenarios 75 | - Session management 76 | - Inventory systems 77 | - Financial applications 78 | - Gaming leaderboards 79 | 80 | ### Deployment 81 | - Kubernetes deployments 82 | - Cloud provider specific guides 83 | - Monitoring and observability 84 | - Performance testing scenarios 85 | 86 | ## Questions? 87 | 88 | If you have questions about contributing: 89 | 1. Join our [Discord community](https://discord.gg/GrRCajJqmQ) 90 | 2. Open a GitHub issue 91 | 3. Ask in the discussions section 92 | 93 | I look forward to your contributions! -------------------------------------------------------------------------------- /examples/banking/README.md: -------------------------------------------------------------------------------- 1 | # Banking Transaction Example 2 | 3 | This example demonstrates atomic bank transfers using Apache Cassandra's ACID transaction capabilities via Accord. It showcases how to maintain consistency when moving money between accounts. 4 | 5 | ## Overview 6 | 7 | The example implements a basic banking system with: 8 | - Account management with transactional support 9 | - Atomic transfers between accounts 10 | - Balance verification before transfers 11 | - Automatic rollback on failures 12 | 13 | ## Schema 14 | 15 | ```sql 16 | CREATE KEYSPACE IF NOT EXISTS banking 17 | WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}; 18 | 19 | CREATE TABLE banking.accounts ( 20 | account_holder text, 21 | account_balance decimal, 22 | PRIMARY KEY (account_holder) 23 | ) WITH transactional_mode = 'full'; 24 | ``` 25 | 26 | ## Quick Start 27 | 28 | 1. Run the setup script: 29 | ```bash 30 | ./setup.sh 31 | ``` 32 | 33 | This will: 34 | - Start a Cassandra container with Accord support 35 | - Create the banking keyspace and tables 36 | - Load sample account data 37 | - Verify the setup 38 | 39 | 2. Execute a transfer: 40 | ```bash 41 | docker exec -i cassandra-accord cqlsh < transfer.cql 42 | ``` 43 | 44 | ## Included Files 45 | 46 | - `schemas.cql`: Table definitions 47 | - `sample_data.cql`: Initial account data (Bob and Alice with $100 each) 48 | - `transfer.cql`: Example transfer transaction ($20 from Alice to Bob) 49 | - `setup.sh`: Automated setup script 50 | 51 | ## Example Transfer 52 | 53 | The transfer script demonstrates: 54 | - Balance checking before transfer 55 | - Atomic updates to both accounts 56 | - Transaction rollback on insufficient funds 57 | 58 | ```sql 59 | BEGIN TRANSACTION 60 | LET fromBalance = (SELECT account_balance FROM banking.accounts 61 | WHERE account_holder='alice'); 62 | 63 | IF fromBalance.account_balance >= 20 THEN 64 | UPDATE banking.accounts SET account_balance -= 20 65 | WHERE account_holder='alice'; 66 | UPDATE banking.accounts SET account_balance += 20 67 | WHERE account_holder='bob'; 68 | END IF 69 | COMMIT TRANSACTION; 70 | ``` 71 | 72 | ## Implementation Details 73 | 74 | - Transactions automatically roll back if any part fails 75 | - Balance checks prevent overdrafts 76 | - All operations are atomic and isolated 77 | 78 | ## Getting Help 79 | 80 | Check out the [Github Discussions](https://github.com/pmcfadin/awesome-accord/) in the repository or... 81 | 82 | Join our Discord community for support and discussions: 83 | https://discord.gg/GrRCajJqmQ 84 | 85 | ## Next Steps 86 | 87 | Try these scenarios: 88 | - Transfer more money than available 89 | - Run concurrent transfers 90 | - Verify final balances -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # 🐳 Docker Setup for Accord-Enabled Cassandra 2 | 3 | Get started with ACID transactions in Cassandra using our pre-configured Docker image. This guide covers both single-node and multi-node setups. 4 | 5 | ## Quick Start (Single Node) 6 | 7 | ```bash 8 | # Pull the latest image 9 | docker pull pmcfadin/cassandra-accord 10 | 11 | # Start a container 12 | docker run -d \ 13 | --name cassandra-accord \ 14 | -p 9042:9042 \ 15 | pmcfadin/cassandra-accord 16 | 17 | # Connect using cqlsh 18 | docker exec -it cassandra-accord ./bin/cqlsh 19 | ``` 20 | 21 | ## Environment Variables 22 | 23 | Customize your Cassandra instance with these environment variables: 24 | 25 | | Variable | Default | Description | 26 | |----------|---------|-------------| 27 | | MAX_HEAP_SIZE | 512M | Maximum heap size | 28 | | HEAP_NEWSIZE | 100M | New generation heap size | 29 | 30 | Example with custom memory settings: 31 | ```bash 32 | docker run -d \ 33 | --name cassandra-accord \ 34 | -p 9042:9042 \ 35 | -e MAX_HEAP_SIZE=1G \ 36 | -e HEAP_NEWSIZE=200M \ 37 | pmcfadin/cassandra-accord 38 | ``` 39 | 40 | ## Data Persistence 41 | 42 | Mount volumes to persist your data: 43 | 44 | ```bash 45 | docker run -d \ 46 | --name cassandra-accord \ 47 | -p 9042:9042 \ 48 | -v $(pwd)/cassandra-data:/opt/cassandra/data \ 49 | pmcfadin/cassandra-accord 50 | ``` 51 | 52 | ## Multi-Node Setup 53 | 54 | Use our docker-compose.yml to run a multi-node cluster: 55 | 56 | ```bash 57 | # Start a 3-node cluster 58 | docker-compose up -d 59 | 60 | # Scale to more nodes 61 | docker-compose up -d --scale cassandra=3 62 | ``` 63 | 64 | ## 🔍 Ports 65 | 66 | | Port | Description | 67 | |------|-------------| 68 | | 9042 | CQL native transport | 69 | | 7000 | Inter-node communication | 70 | | 7001 | TLS inter-node communication | 71 | | 7199 | JMX | 72 | 73 | ## Advanced Configuration 74 | 75 | ### Custom cassandra.yaml 76 | 77 | 1. Extract the default configuration: 78 | ```bash 79 | docker cp cassandra-accord:/opt/cassandra/conf/cassandra.yaml ./cassandra.yaml 80 | ``` 81 | 82 | 2. Start with custom config: 83 | ```bash 84 | docker run -d \ 85 | --name cassandra-accord \ 86 | -p 9042:9042 \ 87 | -v $(pwd)/cassandra.yaml:/opt/cassandra/conf/cassandra.yaml \ 88 | pmcfadin/cassandra-accord 89 | ``` 90 | 91 | ## Trying New Syntax 92 | 93 | Try the examples after connecting and see how the new transaction syntax works. 94 | 95 | 96 | ## Need Help? 97 | - Check out the [Github Discussions](https://github.com/pmcfadin/awesome-accord/) in the repository 98 | - Join our [Discord](https://discord.gg/GrRCajJqmQ) for real-time support 99 | - Check the [Troubleshooting Guide](../docs/troubleshooting.md) 100 | - Report issues on GitHub -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quick Start with Accord Transactions 2 | 3 | This guide will get you up and running with Accord transactions in minutes. We'll cover setup, basic usage, and your first transaction. 4 | 5 | ## Prerequisites 6 | 7 | - Docker installed (for single-node testing) 8 | - OR Homebrew (for multi-node setup) 9 | - Basic familiarity with CQL 10 | 11 | ## Setup Options 12 | 13 | ### Option 1: Docker (Single Node) 14 | ```bash 15 | # Pull and run the container 16 | docker pull pmcfadin/cassandra-accord 17 | docker run -d --name cassandra-accord -p 9042:9042 pmcfadin/cassandra-accord 18 | 19 | # Connect with cqlsh 20 | docker exec -it cassandra-accord ./bin/cqlsh 21 | ``` 22 | 23 | ### Option 2: Multi-Node Lab (via easy-cass-lab) 24 | ```bash 25 | # Install easy-cass-lab 26 | brew tap rustyrazorblade/rustyrazorblade 27 | brew install easy-cass-lab 28 | 29 | # Create a new cluster 30 | mkdir my-cluster && cd my-cluster 31 | easy-cass-lab init -c 3 -s 1 mycluster 32 | easy-cass-lab up 33 | ``` 34 | 35 | ## Your First Transaction 36 | 37 | Let's create a simple inventory management system: 38 | 39 | ```sql 40 | -- Create a table with transactions enabled 41 | CREATE TABLE demo.products ( 42 | item text, 43 | inventory_count decimal, 44 | PRIMARY KEY (item) 45 | ) WITH transactional_mode = 'full'; 46 | 47 | -- Insert initial inventory 48 | INSERT INTO demo.products(item, inventory_count) 49 | VALUES ('PlayStation 5', 100); 50 | 51 | -- Run a transaction to update inventory 52 | BEGIN TRANSACTION 53 | UPDATE demo.products 54 | SET inventory_count -= 1 55 | WHERE item='PlayStation 5'; 56 | COMMIT TRANSACTION; 57 | 58 | -- Verify the result 59 | SELECT * FROM demo.products WHERE item='PlayStation 5'; 60 | ``` 61 | 62 | ## Example Transactions 63 | 64 | 1. **Bank Transfer** 65 | ```sql 66 | BEGIN TRANSACTION 67 | UPDATE accounts SET balance -= 100 WHERE user_id = 'alice'; 68 | UPDATE accounts SET balance += 100 WHERE user_id = 'bob'; 69 | COMMIT TRANSACTION; 70 | ``` 71 | 72 | 2. **User Registration** 73 | ```sql 74 | BEGIN TRANSACTION 75 | LET existing = (SELECT email FROM users WHERE email = 'new@example.com'); 76 | 77 | IF existing IS NULL THEN 78 | INSERT INTO users(id, email) VALUES (uuid(), 'new@example.com'); 79 | END IF 80 | COMMIT TRANSACTION; 81 | ``` 82 | 83 | ## Next Steps 84 | 85 | - Explore more [Use Cases](use-cases.md) 86 | - Learn about [Transaction Patterns](patterns.md) 87 | - Read about [Performance Tuning](performance.md) 88 | - Join our [Discord](https://discord.gg/GrRCajJqmQ) community 89 | 90 | ## Getting Help 91 | - Check out the [Github Discussions](https://github.com/pmcfadin/awesome-accord/) in the repository 92 | - Check our [Troubleshooting](troubleshooting.md) guide 93 | - Ask in our [Discord](https://discord.gg/GrRCajJqmQ) channel 94 | - Review [Common Issues](troubleshooting.md#common-issues) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Awesome Accord: ACID Transactions in Apache Cassandra 2 | 3 | Welcome to the Awesome Accord repository! This guide provides resources and examples for implementing ACID transactions in Apache Cassandra. Learn how to leverage distributed transactions for building reliable applications. 4 | 5 | ## What's Inside 6 | 7 | - **Quick Start with Docker**: Single-node deployment for immediate testing 8 | - **Lab Environment**: Multi-node cluster setup for development 9 | - **Use Cases & Examples**: Production-ready implementations 10 | - **Learning Resources**: Documentation and best practices 11 | 12 | ## ⚠️ Warning and Disclaimer ⚠️ 13 | Accord is in active development and still a feature branch in the Apasche Cassandra® Repo. You will find bug. What we ask is that you help with a contribution of a bug report. 14 | 15 | You can use the [Github discussions](https://github.com/pmcfadin/awesome-accord/discussions) bug report forum for this or use the Planet Cassandra Discord channel for accord listed below. A bug report should have the folowing: 16 | - The data model used 17 | - Actions to reproduce the bug 18 | - Full stack trace from system.log 19 | 20 | If you have suggestions about syntax or improving the overall developer expirience, we want to hear about that to! Add it as a suggestion or feature request using [Github discussions](https://github.com/pmcfadin/awesome-accord/discussions) or let us know in the Planet Cassandra Discord. 21 | 22 | Now, on to the fun! 23 | 24 | ## Quick Start Options 25 | 26 | ### Option 1: Docker (Single Node) 27 | ```bash 28 | docker pull pmcfadin/cassandra-accord 29 | docker run -d --name cassandra-accord -p 9042:9042 pmcfadin/cassandra-accord 30 | ``` 31 | 32 | ### Option 2: Multi-Node Lab Environment 33 | ```bash 34 | brew tap rustyrazorblade/rustyrazorblade 35 | brew install easy-cass-lab 36 | ``` 37 | 38 | ## Featured Use Cases 39 | 40 | - **Banking Transactions**: Account transfers with ACID guarantees 41 | - **Inventory Management**: Race-free inventory tracking 42 | - **User Management**: Multi-table atomic operations 43 | 44 | ## Community 45 | 46 | - Provide feedback and bug reports in the [repository forum](https://github.com/pmcfadin/awesome-accord/discussions) 47 | - [Join our Discord Community](https://discord.gg/GrRCajJqmQ) for discussions and support 48 | - Review our [Contributor Guide](./CONTRIBUTING.md) 49 | - Submit issues and improvements through GitHub 50 | 51 | ## Repository Structure 52 | 53 | ``` 54 | / 55 | ├── docker/ # Docker configuration and setup 56 | ├── easy-cass-lab/ # Multi-node testing environment 57 | ├── examples/ # Implementation examples 58 | │ ├── banking/ # Financial transaction examples 59 | │ ├── inventory/ # Stock management examples 60 | │ └── user-mgmt/ # User operations examples 61 | └── docs/ # Guides and documentation 62 | ``` 63 | 64 | ## Documentation 65 | 66 | Our [documentation](./docs/README.md) includes: 67 | - Comprehensive setup instructions 68 | - Transaction patterns and implementations 69 | - Performance optimization guides 70 | - Troubleshooting and best practices 71 | 72 | ## Getting Started 73 | 74 | 1. Choose your deployment option: 75 | - [Docker Guide](./docker/README.md) 76 | - [Easy-Cass-Lab Guide](./easy-cass-lab/README.md) 77 | 2. Follow the [Quick Start Guide](./docs/quickstart.md) 78 | 3. Explore [example implementations](./examples/) 79 | 4. Connect with our [Discord community](https://discord.gg/GrRCajJqmQ) 80 | 5. Feedback! [Github Discussions](https://github.com/pmcfadin/awesome-accord/discussions) 81 | 82 | ## Example Code 83 | 84 | ```sql 85 | BEGIN TRANSACTION 86 | LET fromBalance = (SELECT account_balance 87 | FROM ks.accounts 88 | WHERE account_holder='alice'); 89 | 90 | IF fromBalance.account_balance >= 20 THEN 91 | UPDATE ks.accounts 92 | SET account_balance -= 20 93 | WHERE account_holder='alice'; 94 | 95 | UPDATE ks.accounts 96 | SET account_balance += 20 97 | WHERE account_holder='bob'; 98 | END IF 99 | COMMIT TRANSACTION; 100 | ``` 101 | 102 | ## License 103 | 104 | Apache License 2.0 -------------------------------------------------------------------------------- /docs/use-cases.md: -------------------------------------------------------------------------------- 1 | # Common Use Cases for Accord Transactions 2 | 3 | This guide explores real-world use cases for Accord transactions in Cassandra, with complete examples and best practices. 4 | 5 | ## Financial Transactions 6 | 7 | ### Bank Transfer Example 8 | Atomically move money between accounts while preventing overdrafts. 9 | 10 | ```sql 11 | CREATE TABLE accounts ( 12 | account_holder text, 13 | account_balance decimal, 14 | PRIMARY KEY (account_holder) 15 | ) WITH transactional_mode = 'full'; 16 | 17 | BEGIN TRANSACTION 18 | LET fromBalance = (SELECT account_balance 19 | FROM accounts 20 | WHERE account_holder='alice'); 21 | 22 | IF fromBalance.account_balance >= 20 THEN 23 | UPDATE accounts SET account_balance -= 20 24 | WHERE account_holder='alice'; 25 | 26 | UPDATE accounts SET account_balance += 20 27 | WHERE account_holder='bob'; 28 | END IF 29 | COMMIT TRANSACTION; 30 | ``` 31 | 32 | **Key Benefits:** 33 | - Atomic updates across accounts 34 | - Prevent overdrafts with balance checks 35 | - Consistent view of balances 36 | 37 | ## Inventory Management 38 | 39 | ### Product Inventory Example 40 | Manage product inventory with safe concurrent updates. 41 | 42 | ```sql 43 | CREATE TABLE products ( 44 | item text, 45 | inventory_count decimal, 46 | PRIMARY KEY (item) 47 | ) WITH transactional_mode = 'full'; 48 | 49 | CREATE TABLE shopping_cart ( 50 | user_name text, 51 | item text, 52 | item_count decimal, 53 | PRIMARY KEY (user_name, item) 54 | ) WITH transactional_mode = 'full'; 55 | 56 | BEGIN TRANSACTION 57 | LET inventory = (SELECT inventory_count 58 | FROM products 59 | WHERE item='PlayStation 5'); 60 | 61 | IF inventory.inventory_count > 0 THEN 62 | UPDATE products SET inventory_count -= 1 63 | WHERE item='PlayStation 5'; 64 | 65 | INSERT INTO shopping_cart(user_name, item, item_count) 66 | VALUES ('user123', 'PlayStation 5', 1); 67 | END IF 68 | COMMIT TRANSACTION; 69 | ``` 70 | 71 | **Key Benefits:** 72 | - Prevent overselling 73 | - Atomic cart updates 74 | - Safe concurrent access 75 | 76 | ## User Management 77 | 78 | ### User Registration Example 79 | Maintain unique user records across multiple tables. 80 | 81 | ```sql 82 | CREATE TABLE user ( 83 | user_id UUID, 84 | email text, 85 | country text, 86 | city text, 87 | PRIMARY KEY (user_id) 88 | ) WITH transactional_mode = 'full'; 89 | 90 | CREATE TABLE user_by_email ( 91 | email text, 92 | user_id UUID, 93 | PRIMARY KEY (email) 94 | ) WITH transactional_mode = 'full'; 95 | 96 | BEGIN TRANSACTION 97 | LET existCheck = (SELECT user_id 98 | FROM user_by_email 99 | WHERE email='new@example.com'); 100 | 101 | IF existCheck IS NULL THEN 102 | INSERT INTO user(user_id, email, country, city) 103 | VALUES (uuid(), 'new@example.com', 'US', 'NYC'); 104 | 105 | INSERT INTO user_by_email(email, user_id) 106 | VALUES ('new@example.com', uuid()); 107 | END IF 108 | COMMIT TRANSACTION; 109 | ``` 110 | 111 | **Key Benefits:** 112 | - Ensure email uniqueness 113 | - Atomic multi-table updates 114 | - Consistent secondary indexes 115 | 116 | ## Accurate Counting 117 | 118 | ### Counter Management Example 119 | Implement accurate counters without using Cassandra's counter type. 120 | 121 | ```sql 122 | CREATE TABLE counters ( 123 | counter_name text, 124 | value decimal, 125 | PRIMARY KEY (counter_name) 126 | ) WITH transactional_mode = 'full'; 127 | 128 | BEGIN TRANSACTION 129 | UPDATE counters 130 | SET value += 1 131 | WHERE counter_name='visitors'; 132 | COMMIT TRANSACTION; 133 | ``` 134 | 135 | **Key Benefits:** 136 | - Accurate incrementing/decrementing 137 | - No lost updates 138 | - Consistent reads 139 | 140 | ## Best Practices 141 | 142 | 1. **Keep Transactions Short** 143 | - Minimize the number of operations 144 | - Avoid long-running transactions 145 | 146 | 2. **Use Appropriate Indexes** 147 | - Create indexes on frequently queried columns 148 | - Consider denormalization for performance 149 | 150 | 3. **Handle Failures** 151 | - Implement retry logic 152 | - Use timeouts appropriately 153 | - Log transaction failures 154 | 155 | 4. **Monitor Performance** 156 | - Track transaction latency 157 | - Monitor conflict rates 158 | - Adjust based on metrics 159 | 160 | ## Additional Resources 161 | 162 | - Join our [Discord](https://discord.gg/GrRCajJqmQ) for real-time support 163 | - Check out the [Troubleshooting Guide](troubleshooting.md) 164 | - Explore the [Example Code](../examples/) -------------------------------------------------------------------------------- /docs/cassandra_transactional_guide.md: -------------------------------------------------------------------------------- 1 | 2 | # Apache Cassandra as a Transactional Database 3 | 4 | ## Introduction 5 | Welcome to Apache Cassandra! This guide introduces its transactional capabilities, helping you understand how to leverage these features for robust application development. 6 | 7 | ## Getting Started 8 | ### Setting Up Transactional Tables 9 | 10 | You will need a distribution of Apache Cassandra that includes Accord. The Docker image in this repository is purpose built for that. 11 | 12 | When defining tables, you must flag them as having transactional capabilities: 13 | ```sql 14 | CREATE TABLE demo.tbl ( 15 | col TEXT PRIMARY KEY 16 | ) WITH TRANSACTIONAL_MODE = 'full'; 17 | ``` 18 | 19 | #### Transactional Modes: 20 | There are a few modes to know about, but the default you should use is "full" 21 | 22 | - `off`: Transactions disabled. 23 | - `unsafe`: Permits non-serial writes but can lead to inconsistencies. 24 | - `full`: Ensures serializable semantics for all queries. 25 | 26 | --- 27 | 28 | ## Working with Transactions 29 | ### Transaction Syntax 30 | Example: 31 | ```sql 32 | BEGIN TRANSACTION 33 | LET existing_user = (SELECT user FROM demo.users WHERE user = 'demo@example.com'); 34 | 35 | IF existing_user IS NULL THEN 36 | INSERT INTO demo.users (user, first_name, last_name) 37 | VALUES ('demo@example.com', 'John', 'Doe'); 38 | INSERT INTO demo.folders (user, folder_name) 39 | VALUES ('demo@example.com', 'Documents'); 40 | END IF 41 | COMMIT TRANSACTION; 42 | ``` 43 | 44 | ### Key Points: 45 | - BEGIN TRANSACTION and COMMIT TRANSACTION contain the operations. 46 | - LET syntax allows you to gather the current state while exclusive 47 | - IF statement gives the end user the ability to be selective in what DML is executed based on the data collected in the LET 48 | - Atomic modifications across multiple tables. 49 | - Enforce data relationships via transactions. 50 | 51 | --- 52 | 53 | ## Use Cases 54 | 55 | ### Use Case 1: Accurate Counting 56 | Manage inventory counts with atomic increments and decrements under contention. 57 | ```sql 58 | CREATE TABLE ks.products ( 59 | item text, 60 | inventory_count decimal, 61 | PRIMARY KEY (item) 62 | ) WITH transactional_mode = 'full'; 63 | 64 | INSERT INTO ks.products(item, inventory_count) VALUES ('PlayStation 5', 100); 65 | 66 | -- Increment Inventory 67 | BEGIN TRANSACTION 68 | UPDATE ks.products SET inventory_count += 1 WHERE item='PlayStation 5'; 69 | COMMIT TRANSACTION; 70 | 71 | -- Decrement Inventory 72 | BEGIN TRANSACTION 73 | UPDATE ks.products SET inventory_count -= 1 WHERE item='PlayStation 5'; 74 | COMMIT TRANSACTION; 75 | ``` 76 | 77 | --- 78 | 79 | ### Use Case 2: Bank Transfer 80 | Perform atomic transfers between accounts, ensuring funds are either fully moved or not at all. 81 | ```sql 82 | CREATE TABLE ks.accounts ( 83 | account_holder text, 84 | account_balance decimal, 85 | PRIMARY KEY (account_holder) 86 | ) WITH transactional_mode = 'full'; 87 | 88 | INSERT INTO ks.accounts(account_holder, account_balance) VALUES ('bob', 100); 89 | INSERT INTO ks.accounts(account_holder, account_balance) VALUES ('alice', 100); 90 | 91 | BEGIN TRANSACTION 92 | LET fromBalance = (SELECT account_balance FROM ks.accounts WHERE account_holder='alice'); 93 | 94 | IF fromBalance.account_balance >= 20 THEN 95 | UPDATE ks.accounts SET account_balance -= 20 WHERE account_holder='alice'; 96 | UPDATE ks.accounts SET account_balance += 20 WHERE account_holder='bob'; 97 | END IF 98 | COMMIT TRANSACTION; 99 | 100 | -- Verify Balances 101 | SELECT account_balance FROM ks.accounts WHERE account_holder='alice'; 102 | SELECT account_balance FROM ks.accounts WHERE account_holder='bob'; 103 | ``` 104 | 105 | --- 106 | 107 | ### Use Case 3: Inventory Management 108 | Avoid race conditions while managing inventory in distributed systems. 109 | ```sql 110 | CREATE TABLE ks.products ( 111 | item text, 112 | inventory_count decimal, 113 | PRIMARY KEY (item) 114 | ) WITH transactional_mode = 'full'; 115 | 116 | CREATE TABLE ks.shopping_cart ( 117 | user_name text, 118 | item text, 119 | item_count decimal, 120 | PRIMARY KEY (user_name, item) 121 | ) WITH transactional_mode = 'full'; 122 | 123 | INSERT INTO ks.products(item, inventory_count) VALUES ('PlayStation 5', 100); 124 | 125 | BEGIN TRANSACTION 126 | LET inventory = (SELECT inventory_count FROM ks.products WHERE item='PlayStation 5'); 127 | 128 | IF inventory.inventory_count > 0 THEN 129 | UPDATE ks.products SET inventory_count -= 1 WHERE item='PlayStation 5'; 130 | INSERT INTO ks.shopping_cart(user_name, item, item_count) VALUES ('patrick', 'PlayStation 5', 1); 131 | END IF 132 | COMMIT TRANSACTION; 133 | ``` 134 | 135 | --- 136 | 137 | ### Use Case 4: Real Atomic Batch 138 | Store and retrieve user data across multiple tables with atomic updates. 139 | ```sql 140 | CREATE TABLE ks.user ( 141 | user_id UUID, 142 | email text, 143 | country text, 144 | city text, 145 | PRIMARY KEY (user_id) 146 | ) WITH transactional_mode = 'full'; 147 | 148 | CREATE TABLE ks.user_by_email ( 149 | email text, 150 | user_id UUID, 151 | PRIMARY KEY (email) 152 | ) WITH transactional_mode = 'full'; 153 | 154 | CREATE TABLE ks.user_by_location ( 155 | country text, 156 | city text, 157 | user_id UUID, 158 | PRIMARY KEY ((country, city), user_id) 159 | ) WITH transactional_mode = 'full'; 160 | 161 | BEGIN TRANSACTION 162 | LET existCheck = (SELECT user_id FROM ks.user_by_email WHERE email='patrick@datastax.com'); 163 | 164 | IF existCheck IS NULL THEN 165 | INSERT INTO ks.user(user_id, email, country, city) 166 | VALUES (94813846-4366-11ed-b878-0242ac120002, 'patrick@datastax.com', 'US', 'Windsor'); 167 | 168 | INSERT INTO ks.user_by_email(email, user_id) 169 | VALUES ('patrick@datastax.com', 94813846-4366-11ed-b878-0242ac120002); 170 | 171 | INSERT INTO ks.user_by_location(country, city, user_id) 172 | VALUES ('US', 'Windsor', 94813846-4366-11ed-b878-0242ac120002); 173 | END IF 174 | COMMIT TRANSACTION; 175 | 176 | SELECT * FROM ks.user; 177 | ``` 178 | 179 | --- 180 | 181 | ## Conclusion 182 | Apache Cassandra's transactional capabilities simplify building scalable, reliable applications. Explore these features to enhance your application's consistency and performance. 183 | 184 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------