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:
- Validation Phase: The transaction checks vault write permissions, validates vector dimensions, and prepares undo records.
- WAL Logging: All batched operations are written to the Write-Ahead Log (WAL) with a transaction sequence marker.
- Memory Application: Vectors are inserted into HNSW indices and payload stores across target collections.
- 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();
}
}