## Module 7: Using Branching to Accelerate Innovation

![demo_203-tidb-x-branching.jpg 85%](https://lab-static.pingcap.com/images/2025/11/27/c5caa8e851e261578fb8ca4576db01916c173685.jpg)

> [!NOTE]
> This module introduces a feature that is currently in preview.

This module demonstrates how the branching capability can significantly improve the efficiency of development.

A branch is a separate cluster instance that contains its own copy of data diverged from the original cluster. This isolated environment enables you to experiment and test changes safely, without impacting the primary cluster. In this module, you will create three independent branches from the current database and run parallel tests of three different inventory solutions on each branch.

### Step 1. Create branches

- Go to the [Clusters page](https://tidbcloud.com/project/clusters) in your TiDB Cloud console and click the name of your lab cluster. If you started the lab by choosing `Create New Cluster`, the cluster name will be `${LAB:SERVERLESS_CLUSTER_NAME}`.

![Demo-RU-001.png 85%](https://lab-static.pingcap.com/images/2025/11/24/9c016ddc77e89cb9d9ae0669890d36cb316f6d20.png)

- Click on the cluster name `${LAB:SERVERLESS_CLUSTER_NAME}`, then select `Overview` in the upper left corner.

![Demo-RU-002.png 85%](https://lab-static.pingcap.com/images/2025/11/24/8d064cdda27759df1640171cbf92f7d340e4364d.png)

- Click the `Branches` tab on the left to open the Branches Panel.

![demo_branch_UI_01.png 85%](https://lab-static.pingcap.com/images/2025/11/27/c094e9effcea9e16423f52268a3f03be1d9f27fe.png)

- In the Branches panel, click the `Create Branch` button on the top right of the window to create a new branch.

![demo_branch_UI_02.png 85%](https://lab-static.pingcap.com/images/2025/11/27/544986b0dc326f95d55e8674dd3b403630801592.png)

- In the pop-up Create Branch window, enter `test-branch-1` in the Name field, select `main` in the Parent branch field, select `Current point in time` in the Include data up to field, this creates a branch named `test-branch-1` with a data snapshot of the database at the current point in time. Then click the Create button.

![demo_branch_UI_03.png 50%](https://lab-static.pingcap.com/images/2025/11/27/1a617fd5c838b7b4559866a7196edf6fb4b71aaf.png)

- Repeat the steps above to create a branch named `test-branch-2` with a data snapshot at the current point in time.

![demo_branch_UI_04.png 50%](https://lab-static.pingcap.com/images/2025/11/27/f14658cf6af60b5bebde97b0c9baeb72196855a0.png)

- Repeat the steps above to create a branch named `test-branch-3` with a data snapshot at the current point in time.

![demo_branch_UI_05.png 50%](https://lab-static.pingcap.com/images/2025/11/27/067cc091c2c27bb173c4b1d47ecaefee42b79e5a.png)

- Return to the Branches Panel and observe the three newly created branches, paying attention to their Status column.

![demo_branch_UI_06.png 85%](https://lab-static.pingcap.com/images/2025/11/27/5719c270a2536174780784e9ec2c970d0baa51ef.png)

- When all three branches show `Active` in the Status column, they are ready for use.

![demo_branch_UI_07.png 85%](https://lab-static.pingcap.com/images/2025/11/27/7316875a385eb9453c8d5985677bdb5739f1c1e0.png)

### Step 2. Connect to all branches

- In the Branches Panel, Select `test-branch-1`, click `...` in the Action column, then select `Connect`.

![demo_branch_UI_08.png 85%](https://lab-static.pingcap.com/images/2025/11/27/fcc16837cc8a9500b11dfce73d167fa16664ba49.png)

- Click `Generate Password` in the pop-up window.

![demo_branch_UI_09.png 85%](https://lab-static.pingcap.com/images/2025/11/27/acda36b4b8b64f0e63910a71ee3a51bca663a969.png)

- After the password is generated, select `Connect with .env` and click `copy` icon.

![env-file-branch-1.jpg 50%](https://lab-static.pingcap.com/images/2025/12/2/d16d8e8bca04b77d597b2df188502031c49dd771.jpg)

- In [Terminal 1](ssh://monitor1-ssh#1), paste the copied `test-branch-1` connection information to set the environment variable values. The output should resemble the following example:

  ```output
  ubuntu@ip-10-90-1-65:~$ DB_HOST=gateway01.us-west-2.prod.aws.tidbcloud.com
  DB_PORT=4000
  DB_USERNAME='3NViMyHWFBkJvQq.root'
  DB_PASSWORD='1Pbcc4CFXTtnZA4C'
  DB_DATABASE='lab_demo_203_6930011'
  ```

- Stay in [Terminal 1](ssh://monitor1-ssh#1), execute the following command to save the `test-branch-1` connection environment variables to `.env-1` file.

  ```bash
  cat > .env-1 <<EOF
  BRANCH_HOST=$DB_HOST
  BRANCH_PORT=$DB_PORT
  BRANCH_USERNAME=$DB_USERNAME
  BRANCH_PASSWORD=$DB_PASSWORD
  BRANCH_DATABASE=${LAB:SERVERLESS_CLUSTER_DATABASE_NAME}
  EOF
  ```

- Repeat the same steps for `test-branch-2`. Generate password first, then select `Connect with .env`, and click `copy` icon.

![env-file-branch-2.jpg 50%](https://lab-static.pingcap.com/images/2025/12/2/3eac0b2ee150121143fe91b4b514bbecc617e5fc.jpg)

- Click [Terminal 2](ssh://monitor1-ssh#2), paste the copied `test-branch-2` connection information to assign values to environment variables. The output should resemble the following example:

  ```output
  ubuntu@ip-10-90-1-65:~$ DB_HOST=gateway01.us-west-2.prod.aws.tidbcloud.com
  DB_PORT=4000
  DB_USERNAME='zxBRD32X3wj8KRY.root'
  DB_PASSWORD='PvNnqFGh63rAX4RK'
  DB_DATABASE='lab_demo_203_6930011'
  ```

- Stay in [Terminal 2](ssh://monitor1-ssh#2), execute the following command to save the `test-branch-2` connection environment variables to `.env-2` file.

  ```bash
  cat > .env-2 <<EOF
  BRANCH_HOST=$DB_HOST
  BRANCH_PORT=$DB_PORT
  BRANCH_USERNAME=$DB_USERNAME
  BRANCH_PASSWORD=$DB_PASSWORD
  BRANCH_DATABASE=${LAB:SERVERLESS_CLUSTER_DATABASE_NAME}
  EOF
  ```

- Repeat the same steps for `test-branch-3`. Generate password first, then select `Connect with .env`, and click `copy` icon.

![env-file-branch-3.jpg 50%](https://lab-static.pingcap.com/images/2025/12/2/2c0584b8494b0cfaf347cc86203f0fb991e1d032.jpg)

- Click [Terminal 3](ssh://monitor1-ssh#3), paste the copied `test-branch-3` connection information to assign values to environment variables. The output should resemble the following example:

  ```output
  ubuntu@ip-10-90-1-65:~$ DB_HOST=gateway01.us-west-2.prod.aws.tidbcloud.com
  DB_PORT=4000
  DB_USERNAME='2SE7X5kxT7oxJU5.root'
  DB_PASSWORD='AlrsLuPTxy76zFdI'
  DB_DATABASE='lab_demo_203_6930011'
  ```

- Stay in [Terminal 3](ssh://monitor1-ssh#3), execute the following command to save the `test-branch-3` connection environment variables to `.env-3` file.

  ```bash
  cat > .env-3 <<EOF
  BRANCH_HOST=$DB_HOST
  BRANCH_PORT=$DB_PORT
  BRANCH_USERNAME=$DB_USERNAME
  BRANCH_PASSWORD=$DB_PASSWORD
  BRANCH_DATABASE=${LAB:SERVERLESS_CLUSTER_DATABASE_NAME}
  EOF
  ```

- In any terminal, confirm that three environment files contain connection information for 3 branches are set correctly. You should see three different usernames.

  ```bash
  cat .env-1 .env-2 .env-3 | grep BRANCH_USERNAME
  ```

  ```output
  BRANCH_USERNAME=XXXXXXXXXXXXXXX.root
  BRANCH_USERNAME=YYYYYYYYYYYYYYY.root
  BRANCH_USERNAME=ZZZZZZZZZZZZZZZ.root
  ```

- On [Terminal 1](ssh://monitor1-ssh#1), connect to `test-branch-1`.

  ```bash
  source .env-1
  mysql \
  --comments -u $BRANCH_USERNAME -p$BRANCH_PASSWORD \
   -h $BRANCH_HOST -P $BRANCH_PORT \
   --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/certs/ca-certificates.crt
  ```

  ```output
  mysql>
  ```

- On `test-branch-1`, and set the transaction isolation level to committed read.

  ```sql
  SET GLOBAL transaction_isolation = 'READ-COMMITTED';
  SHOW GLOBAL VARIABLES LIKE 'transaction_isolation';
  EXIT
  ```

  ```output
  Query OK, 0 rows affected (0.18 sec)

  +-----------------------+----------------+
  | Variable_name         | Value          |
  +-----------------------+----------------+
  | transaction_isolation | READ-COMMITTED |
  +-----------------------+----------------+
  1 row in set (0.16 sec)

  Bye
  ```

- On [Terminal 2](ssh://monitor1-ssh#2), connect to `test-branch-2`.

  ```bash
  source .env-2
  mysql \
  --comments -u $BRANCH_USERNAME -p$BRANCH_PASSWORD \
   -h $BRANCH_HOST -P $BRANCH_PORT \
   --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/certs/ca-certificates.crt
  ```

  ```output
  mysql>
  ```

- On `test-branch-2`, set the transaction isolation level to committed read.

  ```sql
  SET GLOBAL transaction_isolation = 'READ-COMMITTED';
  SHOW GLOBAL VARIABLES LIKE 'transaction_isolation';
  EXIT
  ```

  ```output
  Query OK, 0 rows affected (0.18 sec)

  +-----------------------+----------------+
  | Variable_name         | Value          |
  +-----------------------+----------------+
  | transaction_isolation | READ-COMMITTED |
  +-----------------------+----------------+
  1 row in set (0.16 sec)

  Bye
  ```

- On [Terminal 3](ssh://monitor1-ssh#3), connect to `test-branch-3`.

  ```bash
  source .env-3
  mysql \
  --comments -u $BRANCH_USERNAME -p$BRANCH_PASSWORD \
   -h $BRANCH_HOST -P $BRANCH_PORT \
   --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/certs/ca-certificates.crt
  ```

  ```output
  mysql>
  ```

- On `test-branch-3` and set the transaction isolation level to committed read.

  ```sql
  SET GLOBAL transaction_isolation = 'READ-COMMITTED';
  SHOW GLOBAL VARIABLES LIKE 'transaction_isolation';
  EXIT
  ```

  ```output
  Query OK, 0 rows affected (0.18 sec)

  +-----------------------+----------------+
  | Variable_name         | Value          |
  +-----------------------+----------------+
  | transaction_isolation | READ-COMMITTED |
  +-----------------------+----------------+
  1 row in set (0.16 sec)

  Bye
  ```

### Step 3. Deploy parallel testing across three branches

- With three branches available, you can concurrently test three different inventory deduction solutions  in-parallel.

- Make sure you have three terminals open, [Terminal 1](ssh://monitor1-ssh#1), [Terminal 2](ssh://monitor1-ssh#2), and [Terminal 3](ssh://monitor1-ssh#3).

- Make sure you have three environment files ready for three branches. You completed this task in Step 2. Run the following command on any terminal.

  ```bash
  file .env-1 .env-2 .env-3
  ```

  ```output
  .env-1: ASCII text
  .env-2: ASCII text
  .env-3: ASCII text
  ```

- Deploy the first Python code. This test simulates 8 concurrent sessions purchasing the same product:
  - Check inventory in `book` table using SELECT ... FOR UPDATE to lock the record.
  - Insert an order into `order` table.
  - Reduce inventory from `book` table.
  - All operations complete within a single transaction.

![demo_branch_pic_02.png 50%](https://lab-static.pingcap.com/images/2025/11/27/5dacb92501bf6389d1e7b7c7a2f857801cd2b999.png)

- On [Terminal 1](ssh://monitor1-ssh#1), generate Python code `demo_branch_1_test.py`.

  ```bash
  cat > demo_branch_1_test.py <<'EOF'
  import mysql.connector
  from prettytable import PrettyTable
  import datetime
  import time
  import random
  import threading
  import sys,os
  from dotenv import load_dotenv

  load_dotenv(sys.argv[1])
  branch_host = os.environ.get("BRANCH_HOST")
  branch_port = os.environ.get("BRANCH_PORT")
  branch_username = os.environ.get("BRANCH_USERNAME")
  branch_password = os.environ.get("BRANCH_PASSWORD")
  branch_database = '${LAB:SERVERLESS_CLUSTER_DATABASE_NAME}'

  config = {
    'user': branch_username,
    'password': branch_password,
    'host': branch_host,
    'database': branch_database,
    'raise_on_warnings': False,
    'port': branch_port,
  }

  # Simulate order and inventory processing for a connection, which continuously runs purchase simulations until inventory is depleted.
  def process_order_worker(user_id):
        # Establishing the connection
        conn = mysql.connector.connect(**config, buffered=True)

        try:
            while True:
                cursor = conn.cursor()

                # Enable transaction handling where each purchase activity is completed within a single transaction.
                cursor.execute("BEGIN")

                # Query the inventory of the product to be purchased and apply a lock on the product data.
                cursor.execute("""
                     SELECT stock FROM books
                     WHERE id = 6 FOR UPDATE
                 """)

                result = cursor.fetchone()

                # Check if the product is sold out.
                if not result or result[0] <= 0:
                    print(f"Stock is not enough, Stop!")
                    break

                current_stock = result[0]

                # Generate a random purchase quantity.
                purchase_quantity = random.randint(1, 10)

                if purchase_quantity > current_stock:
                    purchase_quantity = current_stock

                # Create an order record.
                cursor.execute("""
                     INSERT INTO orders(book_id, user_id, quality, ordered_at)
                     VALUES(6, %s, %s, CURRENT_TIMESTAMP)
                               """, (user_id, purchase_quantity,))

                # Reduce inventory.
                cursor.execute("""
                     UPDATE books
                     SET stock = stock - %s
                     WHERE id = 6
                           """,(purchase_quantity,))

                # If the purchase is successful, commit the transaction.
                conn.commit()

                print(f"User {user_id} successfully purchased {purchase_quantity} books, and the current remaining stock is {current_stock - purchase_quantity}")

                time.sleep(random.uniform(0.1, 0.5))

        except Exception as e:
            print(f"User {user_id} got error when process the order.")
            conn.rollback()
        finally:
            conn.close

  def main():

    # Simulate 8 sessions performing purchases concurrently.
    num_threads = 8

    start_time = 0
    end_time = 0

    print(f"Starting {num_threads} database worker threads...")

    # Create and start threads
    threads = []
    for i in range(num_threads):
        thread = threading.Thread(
            target=process_order_worker,
            args=(i + 1,),
            name=f"User-{i+1}",
            daemon=True
        )
        threads.append(thread)
        thread.start()
        print(f"{thread.name} thread started successfully!")

    print(f"All {num_threads} user threads started successfully!")

    start_time = time.time()

    try:
        # Keep the main thread alive - wait for threads to complete (they run indefinitely)
        for thread in threads:
            thread.join()

        end_time = time.time()

        conn = mysql.connector.connect(**config, buffered=True)

        # Print test results and test duration.
        try:
             cursor = conn.cursor()

             cursor.execute("""
                 SELECT stock FROM books
                 WHERE id = 6
             """)
             final_stock = cursor.fetchone()[0]

             cursor.execute("""
                 SELECT COUNT(*) as total_orders FROM orders WHERE book_id = 6
             """)
             total_orders = cursor.fetchone()[0]

             cursor.execute("""
                 SELECT SUM(quality) as total_quantity FROM orders WHERE book_id = 6
             """)
             total_quantity = cursor.fetchone()[0]

             duration_time = end_time - start_time

             print("=======================================")
             print(f"Final stock: {final_stock}")
             print(f"Total orders: {total_orders}")
             print(f"Total purchased books: {total_quantity}")
             print(f"Process duration: {duration_time:.2f} seconds.")
             print("Test finished！")
             print("=======================================")

        except Exception as e:
            print(f"Got error when get summary!")
            conn.rollback()
        finally:
            conn.close

    except KeyboardInterrupt:
        print("\nReceived interrupt signal. Stopping all threads...")
        sys.exit(0)

  if __name__ == "__main__":
    main()
  EOF
  ls -l demo_branch_1_test.py
  ```

  ```output
  -rw-rw-r-- 1 ubuntu ubuntu 4770 Nov 26 10:37 demo_branch_1_test.py
  ```

- Deploy the second testing Python code. This test simulates 8 concurrent sessions purchasing the same product in separate transactions:
  - Check inventory (Transaction 1).
  - Insert order record (Transaction 2).
  - Reduce inventory (Transaction 3).

![demo_branch_pic_03.png 50%](https://lab-static.pingcap.com/images/2025/11/27/5c23d6698ceb6107676abbec140d556fa588e914.png)

- On [Terminal 2](ssh://monitor1-ssh#2), generate Python code `demo_branch_2_test.py`.

  ```bash
  cat > demo_branch_2_test.py <<'EOF'
  import mysql.connector
  from prettytable import PrettyTable
  import datetime
  import time
  import random
  import threading
  import sys,os
  from dotenv import load_dotenv

  load_dotenv(sys.argv[1])
  branch_host = os.environ.get("BRANCH_HOST")
  branch_port = os.environ.get("BRANCH_PORT")
  branch_username = os.environ.get("BRANCH_USERNAME")
  branch_password = os.environ.get("BRANCH_PASSWORD")
  branch_database = '${LAB:SERVERLESS_CLUSTER_DATABASE_NAME}'

  config = {
    'user': branch_username,
    'password': branch_password,
    'host': branch_host,
    'database': branch_database,
    'raise_on_warnings': False,
    'port': branch_port,
  }

  # Simulate order and inventory processing for a connection, which continuously runs purchase simulations until inventory is depleted.
  def process_order_worker(user_id):

        # Establishing the connection
        conn = mysql.connector.connect(**config, buffered=True)

        try:
            while True:
                cursor = conn.cursor()

                # transaction handling where each purchase activity is completed across multiple transactions.
                cursor.execute("BEGIN")

                # Transaction 1: Query the inventory of the product to be purchased.
                cursor.execute("""
                     SELECT stock FROM books
                     WHERE id = 6
                 """)

                result = cursor.fetchone()

                # Check if the product is sold out.
                if not result or result[0] <= 0:
                    print(f"Stock is not enough, Stop!")
                    break

                current_stock = result[0]

                # Generate a random purchase quantity.
                purchase_quantity = random.randint(1, 10)

                if purchase_quantity > current_stock:
                    purchase_quantity = current_stock

                conn.commit()

                # Transaction 2: Create an order record.
                cursor.execute("BEGIN")

                # Reduce inventory.
                cursor.execute("""
                     INSERT INTO orders(book_id, user_id, quality, ordered_at)
                     VALUES(6, %s, %s, CURRENT_TIMESTAMP)
                               """, (user_id, purchase_quantity,))
                conn.commit()

                # Transaction 3: Reduce inventory.
                cursor.execute("BEGIN")

                cursor.execute("""
                     UPDATE books
                     SET stock = stock - %s
                     WHERE id = 6
                           """,(purchase_quantity,))

                # If the purchase is successful, commit the transaction.
                conn.commit()

                print(f"User {user_id} successfully purchased {purchase_quantity} books, and the current remaining stock is {current_stock - purchase_quantity}")

                time.sleep(random.uniform(0.1, 0.5))

        except Exception as e:
            print(f"User {user_id} got error when process the order.")
            conn.rollback()
        finally:
            conn.close

  def main():

    # Simulate 8 sessions performing purchases concurrently.
    num_threads = 8

    start_time = 0
    end_time = 0

    print(f"Starting {num_threads} database worker threads...")

    # Create and start threads
    threads = []
    for i in range(num_threads):
        thread = threading.Thread(
            target=process_order_worker,
            args=(i + 1,),
            name=f"User-{i+1}",
            daemon=True
        )
        threads.append(thread)
        thread.start()
        print(f"{thread.name} thread started successfully!")

    print(f"All {num_threads} user threads started successfully!")

    start_time = time.time()

    # Print test results and test duration.
    try:
        # Keep the main thread alive - wait for threads to complete (they run indefinitely)
        for thread in threads:
            thread.join()

        end_time = time.time()

        conn = mysql.connector.connect(**config, buffered=True)

        try:
             cursor = conn.cursor()

             cursor.execute("""
                 SELECT stock FROM books
                 WHERE id = 6
             """)
             final_stock = cursor.fetchone()[0]

             cursor.execute("""
                 SELECT COUNT(*) as total_orders FROM orders WHERE book_id = 6
             """)
             total_orders = cursor.fetchone()[0]

             cursor.execute("""
                 SELECT SUM(quality) as total_quantity FROM orders WHERE book_id = 6
             """)
             total_quantity = cursor.fetchone()[0]

             duration_time = end_time - start_time

             print("=======================================")
             print(f"Final stock: {final_stock}")
             print(f"Total orders: {total_orders}")
             print(f"Total purchased books: {total_quantity}")
             print(f"Process duration: {duration_time:.2f} seconds.")
             print("Test finished！")
             print("=======================================")

        except Exception as e:
            print(f"Got error when get summary!")
            conn.rollback()
        finally:
            conn.close

    except KeyboardInterrupt:
        print("\nReceived interrupt signal. Stopping all threads...")
        sys.exit(0)

  if __name__ == "__main__":
    main()
  EOF
  ls -l demo_branch_2_test.py
  ```

  ```output
  -rw-rw-r-- 1 ubuntu ubuntu 4922 Nov 26 10:54 demo_branch_2_test.py
  ```

- Deploy the third testing Python code. This test simulates 8 concurrent sessions purchasing the same product:
  - Check inventory without locking.
  - Insert order record into order table.
  - Reduce inventory from `book` table.
  - All operations complete within a single transaction.

![demo_branch_pic_04.png 50%](https://lab-static.pingcap.com/images/2025/11/27/f5b72da437ba5da5fbbc597a5e1fe8cba271e8f9.png)

- On [Terminal 3](ssh://monitor1-ssh#3), generate Python code `demo_branch_3_test.py`.

  ```bash
  cat > demo_branch_3_test.py <<'EOF'
  import mysql.connector
  from prettytable import PrettyTable
  import datetime
  import time
  import random
  import threading
  import sys,os
  from dotenv import load_dotenv

  load_dotenv(sys.argv[1])
  branch_host = os.environ.get("BRANCH_HOST")
  branch_port = os.environ.get("BRANCH_PORT")
  branch_username = os.environ.get("BRANCH_USERNAME")
  branch_password = os.environ.get("BRANCH_PASSWORD")
  branch_database = '${LAB:SERVERLESS_CLUSTER_DATABASE_NAME}'

  config = {
    'user': branch_username,
    'password': branch_password,
    'host': branch_host,
    'database': branch_database,
    'raise_on_warnings': False,
    'port': branch_port,
  }

  # Simulate order and inventory processing for a connection, which continuously runs purchase simulations until inventory is depleted.
  def process_order_worker(user_id):

        # Establishing the connection
        conn = mysql.connector.connect(**config, buffered=True)

        try:
            while True:
                cursor = conn.cursor()

                # Enable transaction handling where each purchase activity is completed within a single transaction.
                cursor.execute("BEGIN")

                # Query the inventory of the product to be purchased without applying a lock on the product data.
                cursor.execute("""
                     SELECT stock FROM books
                     WHERE id = 6
                 """)

                result = cursor.fetchone()

                # Check if the product is sold out.
                if not result or result[0] <= 0:
                    print(f"Stock is not enough, Stop!")
                    break

                current_stock = result[0]

                # Generate a random purchase quantity.
                purchase_quantity = random.randint(1, 10)

                if purchase_quantity > current_stock:
                    purchase_quantity = current_stock

                # Create an order record.
                cursor.execute("""
                     INSERT INTO orders(book_id, user_id, quality, ordered_at)
                     VALUES(6, %s, %s, CURRENT_TIMESTAMP)
                               """, (user_id, purchase_quantity,))

                # Reduce inventory.
                cursor.execute("""
                     UPDATE books
                     SET stock = stock - %s
                     WHERE id = 6
                           """,(purchase_quantity,))

                conn.commit()

                print(f"User {user_id} successfully purchased {purchase_quantity} books, and the current remaining stock is {current_stock - purchase_quantity}")

                time.sleep(random.uniform(0.1, 0.5))

        except Exception as e:
            print(f"User {user_id} got error when process the order.")
            conn.rollback()
        finally:
            conn.close

  def main():

    # Simulate 8 sessions performing purchases concurrently.
    num_threads = 8

    start_time = 0
    end_time = 0

    print(f"Starting {num_threads} database worker threads...")

    # Create and start threads
    threads = []
    for i in range(num_threads):
        thread = threading.Thread(
            target=process_order_worker,
            args=(i + 1,),
            name=f"User-{i+1}",
            daemon=True
        )
        threads.append(thread)
        thread.start()
        print(f"{thread.name} thread started successfully!")

    print(f"All {num_threads} user threads started successfully!")

    start_time = time.time()

    try:
        # Keep the main thread alive - wait for threads to complete (they run indefinitely)
        for thread in threads:
            thread.join()

        end_time = time.time()

        conn = mysql.connector.connect(**config, buffered=True)

        # Print test results and test duration.
        try:
             cursor = conn.cursor()

             cursor.execute("""
                 SELECT stock FROM books
                 WHERE id = 6
             """)
             final_stock = cursor.fetchone()[0]

             cursor.execute("""
                 SELECT COUNT(*) as total_orders FROM orders WHERE book_id = 6
             """)
             total_orders = cursor.fetchone()[0]

             cursor.execute("""
                 SELECT SUM(quality) as total_quantity FROM orders WHERE book_id = 6
             """)
             total_quantity = cursor.fetchone()[0]

             duration_time = end_time - start_time

             print("=======================================")
             print(f"Final stock: {final_stock}")
             print(f"Total orders: {total_orders}")
             print(f"Total purchased books: {total_quantity}")
             print(f"Process duration: {duration_time:.2f} seconds.")
             print("Test finished！")
             print("=======================================")

        except Exception as e:
            print(f"Got error when get summary!")
            conn.rollback()
        finally:
            conn.close

    except KeyboardInterrupt:
        print("\nReceived interrupt signal. Stopping all threads...")
        sys.exit(0)

  if __name__ == "__main__":
    main()
  EOF
  ls -l demo_branch_3_test.py
  ```

  ```output
  -rw-rw-r-- 1 ubuntu ubuntu 4682 Nov 26 11:05 demo_branch_3_test.py
  ```

### Step 4. Run parallel testing

- On [Terminal 1](ssh://monitor1-ssh#1), run `demo_branch_1_test.py` (continue without waiting).

  ```bash
  ~/.venv/bin/python demo_branch_1_test.py .env-1
  ```

  ```output
  Starting 8 database worker threads...
  User-1 thread started successfully!
  User-2 thread started successfully!
  User-3 thread started successfully!
  User-4 thread started successfully!
  User-5 thread started successfully!
  User-6 thread started successfully!
  User-7 thread started successfully!
  User-8 thread started successfully!
  All 8 user threads started successfully!
  User 1 successfully purchased 3 books, and
  ...
  ```

- On [Terminal 2](ssh://monitor1-ssh#2), run `demo_branch_2_test.py` (continue without waiting).

  ```bash
  ~/.venv/bin/python demo_branch_2_test.py .env-2
  ```

  ```output
  Starting 8 database worker threads...
  User-1 thread started successfully!
  User-2 thread started successfully!
  User-3 thread started successfully!
  User-4 thread started successfully!
  User-5 thread started successfully!
  User-6 thread started successfully!
  User-7 thread started successfully!
  User-8 thread started successfully!
  All 8 user threads started successfully!
  User 7 successfully purchased 1 books, and
  ...
  ```

- On [Terminal 3](ssh://monitor1-ssh#3), run `demo_branch_3_test.py` (continue without waiting).

  ```bash
  ~/.venv/bin/python demo_branch_3_test.py .env-3
  ```

  ```output
  Starting 8 database worker threads...
  User-1 thread started successfully!
  User-2 thread started successfully!
  User-3 thread started successfully!
  User-4 thread started successfully!
  User-5 thread started successfully!
  User-6 thread started successfully!
  User-7 thread started successfully!
  User-8 thread started successfully!
  All 8 user threads started successfully!
  ...
  ```

- Monitor all three tests until completion. Back to [Terminal 3](ssh://monitor1-ssh#3) with `test-branch-3`, shortest execution time but inventory drops below zero (oversold) - solution contains errors. Note: Your results may vary from the lab guide. If overselling doesn't occur initially, run tests multiple times.

  ```output
  ...
  User 4 successfully purchased 4 books, and the current remaining stock is 23
  User 7 successfully purchased 7 books, and the current remaining stock is 15
  User 6 successfully purchased 8 books, and the current remaining stock is 5
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  User 2 successfully purchased 8 books, and the current remaining stock is 5
  User 3 successfully purchased 6 books, and the current remaining stock is 7
  Stock is not enough, Stop!
  User 8 successfully purchased 2 books, and the current remaining stock is 0
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  =======================================
  Final stock: -22
  Total orders: 370
  Total purchased books: 2022
  Process duration: 68.15 seconds.
  Test finished！
  =======================================
  ```

- Back to [Terminal 2](ssh://monitor1-ssh#2) with `test-branch-2`, moderate execution time but may show overselling - solution contains errors. Your results may vary from the lab guide. If overselling doesn't occur initially, run tests multiple times.

  ```output
  ...
  User 3 successfully purchased 6 books, and the current remaining stock is 18
  User 8 successfully purchased 3 books, and the current remaining stock is 11
  User 5 successfully purchased 9 books, and the current remaining stock is 1
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  User 2 successfully purchased 4 books, and the current remaining stock is 6
  User 7 successfully purchased 1 books, and the current remaining stock is 0
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  =======================================
  Final stock: -36
  Total orders: 377
  Total purchased books: 2036
  Process duration: 97.72 seconds.
  Test finished！
  =======================================
  ```

- Back to [Terminal 1](ssh://monitor1-ssh#1) with `test-branch-1`, longest execution time but inventory reaches zero correctly - solution works as expected.

  ```output
  ...
  User 5 successfully purchased 6 books, and the current remaining stock is 11
  User 3 successfully purchased 5 books, and the current remaining stock is 6
  User 1 successfully purchased 3 books, and the current remaining stock is 3
  User 6 successfully purchased 2 books, and the current remaining stock is 1
  User 2 successfully purchased 1 books, and the current remaining stock is 0
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  Stock is not enough, Stop!
  =======================================
  Final stock: 0
  Total orders: 363
  Total purchased books: 2000
  Process duration: 181.34 seconds.
  Test finished！
  =======================================
  ```

### Step 5. Proceed to the next testing phase

- In this step, you want to use the successful test results of this module to continue testing subsequent modules, and we need to retain the data regardless of whether the test was successful or unsuccessful.

![demo_branch_pic_05.png 50%](https://lab-static.pingcap.com/images/2025/11/27/1e3707c00fbf73158eddf3f321b37edf31a22ba2.png)

- Since the solution in Terminal 1 performed as expected, use its branch for further testing while preserving all test data.Go to the [Clusters page](https://tidbcloud.com/project/clusters) in your TiDB Cloud console and click the name of your lab cluster. If you started the lab by choosing `Create New Cluster`, the cluster name will be `${LAB:SERVERLESS_CLUSTER_NAME}`.

![Demo-RU-001.png 85%](https://lab-static.pingcap.com/images/2025/11/24/9c016ddc77e89cb9d9ae0669890d36cb316f6d20.png)

- Click on the cluster name `${LAB:SERVERLESS_CLUSTER_NAME}`, then select `Overview` in the upper left corner.

![Demo-RU-002.png 85%](https://lab-static.pingcap.com/images/2025/11/24/8d064cdda27759df1640171cbf92f7d340e4364d.png)

- Click the `Branches` tab on the left to open the Branches Panel.

![demo_branch_UI_01.png 85%](https://lab-static.pingcap.com/images/2025/11/27/c094e9effcea9e16423f52268a3f03be1d9f27fe.png)

- In the Branches panel, click the `Create Branch` button on the top right of the window to create a new branch.

![demo_branch_UI_13.png 85%](https://lab-static.pingcap.com/images/2025/11/27/5009833f8220f1851e54711e7ce3eec3bb8b0e90.png)

- In the pop-up Create Branch window, enter `test-branch-1-1` in the Name field, select `test-branch-1` in the Parent branch field, select `Current point in time` in the Include data up to field, this creates a branch named `test-branch-1-1` with a data snapshot of `test-branch-1` at the current point in time. Then click the Create button.

![demo_branch_UI_14.png 50%](https://lab-static.pingcap.com/images/2025/11/27/ce6719b47458cca94d43ef005bde46298527f39d.png)

- Wait for `test-branch-1-1` status to become `Active`. Use this branch for subsequent testing while preserving `test-branch-1`, `test-branch-2`, and `test-branch-3` for regression testing.

![demo_branch_UI_15.png 85%](https://lab-static.pingcap.com/images/2025/11/27/4d3232d62da501d83d91d9277479b4ddf8dfa798.png)

### Step 6. Cleanup

- Go to the [Clusters page](https://tidbcloud.com/project/clusters) in your TiDB Cloud console and click the name of your lab cluster. If you started the lab by choosing `Create New Cluster`, the cluster name will be `${LAB:SERVERLESS_CLUSTER_NAME}`.

![Demo-RU-001.png 85%](https://lab-static.pingcap.com/images/2025/11/24/9c016ddc77e89cb9d9ae0669890d36cb316f6d20.png)

- Click on the cluster name `${LAB:SERVERLESS_CLUSTER_NAME}`, then select `Overview` in the upper left corner.

![Demo-RU-002.png 85%](https://lab-static.pingcap.com/images/2025/11/24/8d064cdda27759df1640171cbf92f7d340e4364d.png)

- Click the `Branches` tab on the left to open the Branches Panel.

![demo_branch_UI_01.png 85%](https://lab-static.pingcap.com/images/2025/11/27/c094e9effcea9e16423f52268a3f03be1d9f27fe.png)

- In the Branches Panel, select `test-branch-1-1`, click `...` in the `Action` column, select  `Delete`.

![demo_branch_UI_16.png 85%](https://lab-static.pingcap.com/images/2025/11/27/bd50c1b3885fe2492471bc20d2005f327d7a20ad.png)

- Click  `I understand, delete` in the confirmation window.

![demo_branch_UI_17.png 50%](https://lab-static.pingcap.com/images/2025/11/27/72bedd61a6ce908307edb8e6950df88c56466ede.png)

- Repeat the process to delete `test-branch-2`, `test-branch-3`, and `test-branch-1`.

![demo_branch_UI_18.png 85%](https://lab-static.pingcap.com/images/2025/11/27/dc0a91b1c61ac243809ad40a31f73ffca2afa7d8.png)

> [!NOTE]
> In this module, you manually manage and explore the three branches. In upcoming labs, we will demonstrate using API and how AI Agents can automate these tasks, allowing for parallelism on a scale far greater than just three branches. Stay tuned.
