elips/docs
C++ API

C++ Transactions

ELIPS supports atomic, multi-collection transaction write batching via elips::Transaction and elips::TransactionCollection.

Overview

Transactions guarantee Atomicity, Consistency, Isolation, and Durability (ACID) for write operations across multiple collections. Either all vector insertions and removals are committed to disk and memory atomically, or none are applied.

Transaction Class

cpp
class Transaction {
public:
    explicit Transaction(Database& db);
    ~Transaction(); // Automatically rolls back if commit() was not called

    TransactionCollection collection(const std::string& name);
    void commit();
    void rollback() noexcept;
};

TransactionCollection Class

cpp
class TransactionCollection {
public:
    RecordID add(
        const Vector& vector,
        Payload payload = {},
        std::optional<RecordID> id = std::nullopt
    );
    void remove(const RecordID& id);
};

Two-Phase Write Protocol

When txn.commit() is invoked:

  1. Validation Phase: The transaction checks vault write permissions, validates vector dimensions, and prepares undo records.
  2. WAL Logging: All batched operations are written to the Write-Ahead Log (WAL) with a transaction sequence marker.
  3. Memory Application: Vectors are inserted into HNSW indices and payload stores across target collections.
  4. Rollback Recovery: If any stage fails (e.g. disk write failure), all in-memory changes are rolled back using internal undo buffers.

RAII & Exception Safety

Transaction follows RAII. If a Transaction goes out of scope before commit() completes successfully, its destructor automatically triggers rollback().

Complete Code Example

cpp
#include <elips/elips.hpp>
#include <iostream>

void atomic_transfer(elips::Database& db) {
    // Begin transaction handle
    auto txn = db.begin_transaction();

    try {
        // Enqueue operations across multiple collections
        auto users = txn.collection("users");
        auto logs = txn.collection("logs");

        elips::Vector user_vec = {0.1f, 0.2f, 0.3f, 0.4f};
        elips::Vector log_vec = {0.9f, 0.8f, 0.7f, 0.6f};

        users.add(user_vec, {{"user_id", std::string("u_100")}});
        logs.add(log_vec, {{"action", std::string("user_created")}});

        // Commit atomically
        txn.commit();
        std::cout << "Transaction committed successfully!" << std::endl;
    } catch (const elips::ElipsException& ex) {
        std::cerr << "Transaction failed: " << ex.what() << std::endl;
        txn.rollback();
    }
}