PolyJuice: Learned Concurrency Control
- PolyJuice is a learned concurrency control framework that specializes in in-memory OLTP systems by mapping execution context to fine-grained actions.
- It employs offline evolutionary training to select optimal actions for each data access, enabling choices like waiting, read-version, write visibility, and early validation.
- Empirical results show up to 56% throughput improvement over traditional protocols under high contention, highlighting the benefits of workload-specific optimization.
Searching arXiv for the specified Polyjuice paper and related usage of the name. Polyjuice is a learned concurrency control framework for in-memory OLTP systems that specializes concurrency control policy to a target workload through offline training rather than committing to a fixed hand-designed protocol such as optimistic concurrency control, two-phase locking, or IC3-style schemes. It represents concurrency control as a mapping from the execution context of an individual access to a fine-grained action, and searches this policy space with offline evolutionary training to maximize commit throughput while preserving serializability through a fixed Silo-like validation procedure at commit time (Wang et al., 2021).
1. Problem setting and design objective
Concurrency control is a primary performance determinant in in-memory databases, but the performance of standard protocols varies sharply with workload characteristics such as contention, read/write mix, and transaction structure. In the reported TPC-C example, OCC is best at low contention, while it is outperformed under high contention; accordingly, no single concurrency control algorithm is consistently optimal across operating regimes (Wang et al., 2021).
Polyjuice targets this limitation directly. Rather than fixing one protocol or switching among a small set of known algorithms by heuristic rules, it defines a workload-specialized control layer over static stored procedures. The system assumes an in-memory, single-machine, multi-core OLTP engine with shared memory, worker threads, and transaction logic expressed as C++ stored procedures using a Silo-like API: BeginTx, Get, Put, and CommitTx. Transaction types are known a priori, and the learned concurrency control focuses on read-write transactions; read-only transactions are handled separately using snapshot or Silo’s mechanism (Wang et al., 2021).
A central motivation is the inadequacy of coarse-grained hybridization. Prior adaptive systems such as MOCC, Sundial, Tebaldi, CormCC, and Callas partition either by data or by transaction type, then select among a few known protocols. That design leaves no mechanism for mixing concurrency control decisions within a single transaction or even within different accesses to the same object. Polyjuice instead treats concurrency control decisions at the granularity of each static access within each transaction type, allowing per-access choices such as waiting, reading committed or visible uncommitted data, exposing writes early or late, and validating early or only at commit (Wang et al., 2021).
This suggests that Polyjuice should be understood less as a single algorithm than as a framework for synthesizing workload-specific algorithms from a richer search space than conventional protocol design typically considers.
2. Policy space and formalization
Polyjuice defines state as the execution context of a particular data access. The state comprises the transaction type tx_type and a static access identifier acc_id, where acc_id is derived from the program order of Get, Put, and CommitTx calls. If there are transaction types and the -th type has static accesses, then the state-space size is
and each state corresponds to a row of a policy table (Wang et al., 2021).
The action associated with each row has four components. First, a wait action specifies, for each transaction type , either a target access-id or NO_WAIT; when a transaction depends on another transaction of type , it waits until that transaction has executed through the specified access-id. Second, a read-version action selects either CLEAN_READ, which returns the latest committed version, or DIRTY_READ, which returns the latest visible uncommitted version from access lists. Third, a write-visibility action selects either PRIVATE, which keeps writes buffered locally, or PUBLIC, which exposes all buffered writes to per-record access lists. Fourth, an early-validation action determines whether validation is performed after the access (Wang et al., 2021).
The objective is to maximize commit throughput under a fixed workload:
where is the empirically measured throughput of policy 0. Polyjuice is conceptually inspired by reinforcement learning, but the implemented training method is offline search via evolutionary algorithms rather than online RL (Wang et al., 2021).
The per-row action space is combinatorial. Given 1 transaction types with access counts 2, the number of possible wait combinations is 3, and the binary choices for read-version, write-visibility, and early-validation contribute an additional factor of 4. Thus the number of possible action combinations per row is
5
and the full policy-space size is exponential in the number of states, namely 6 (Wang et al., 2021).
Polyjuice also learns a backoff policy for retries after aborts. Its backoff state is defined by transaction type, execution status, and number of prior aborts, and the learned action is a multiplicative update to the per-type backoff time:
7
where the discrete 8 parameters are learned offline (Wang et al., 2021).
3. Execution model, data structures, and correctness
Polyjuice is implemented on top of Silo, replacing Silo’s concurrency control component with a policy-based engine. Runtime state is intentionally minimal for policy lookup: transaction type and access-id. Each worker thread maintains a pointer to the current in-memory policy table, and each access performs an array lookup to retrieve its corresponding action tuple (Wang et al., 2021).
The framework relies on several data structures. Per record, it maintains the latest committed value and a per-object access list containing visible uncommitted writes and reads. Per transaction, it maintains a local read-set T.rset, write-set T.wset, buffered operations T.buffer, a dependency set T.dep, and backoff state. Writes can remain private in T.buffer or become public when flushed to access lists; reads and writes are appended to access lists only after a successful validation point to avoid complicated undo and cascading-abort logic (Wang et al., 2021).
Execution is organized per access. For a PUT, Polyjuice looks up the record, retrieves the policy row for (tx_type, acc_id), applies WaitUntil(action.waits), appends the write to the transaction buffer and write-set, and, if the policy makes writes PUBLIC, performs early validation before flushing buffered operations to access lists. For a GET, the system similarly retrieves the policy row, performs waiting, chooses between committed and visible uncommitted versions according to the read-version action, appends the read to the buffer and read-set, and optionally executes early validation. Early validation itself uses the policy’s validation view, waits on dependencies as needed, and performs an OCC-style validation limited to accesses since the last validation point; on failure, it rolls back to the last successful validation point (Wang et al., 2021).
At commit time, Polyjuice always runs a fixed Silo-like validation protocol. The transaction first ensures that dirty-read dependencies are recorded in T.deps, then waits for all dependent transactions to commit or abort, then locks each record in T.wset, checks version-id stability for each record in T.rset, checks lock conflicts, and aborts on any failure. If validation succeeds, the transaction applies T.wset to the database with unique version-ids and releases locks (Wang et al., 2021).
Correctness is not learned. The learned policy governs interleaving, visibility, and early validation, but serializability is ensured by the fixed commit protocol. The paper sketches a reduction to Silo’s correctness argument: for any Polyjuice-committed transaction 9, there exists a hypothetical Silo transaction 0 that starts after all of 1’s dependencies have committed, observes the same committed state, and passes Silo’s validation iff 2 passes Polyjuice’s. The appendix formulates the argument through serialization-graph dependencies and proves that any serialization-graph edge 3 implies
4
which rules out cycles (Wang et al., 2021).
4. Offline training and policy search
Polyjuice is trained offline rather than inside the production database. The intended workflow is to gather logs of executed transactions and inputs during peak workloads, replay them on a separate training machine, evaluate candidate policies over fixed-length episodes, and evolve the policy table toward higher throughput. The emulation is approximate because interleavings differ from production, but the paper argues that access patterns and contention structure remain sufficiently similar for effective policy search (Wang et al., 2021).
Each individual in the evolutionary algorithm consists of a concurrency control policy table and a backoff policy table. Fitness is commit throughput under the emulated workload. The training loop uses a population of candidate policies, warm-starts from known algorithms encoded in the policy space, mutates policy cells, evaluates resulting policies, and selects the top-performing candidates for the next generation. Mutation flips binary values such as CLEAN_READ versus DIRTY_READ or perturbs integer wait access-ids by a uniformly sampled delta from [-2, 2], clipped to a valid range. The mutation rate and magnitude are decayed over time to promote convergence (Wang et al., 2021).
Warm-starting is important because standard protocols can be embedded directly in the policy space. OCC is approximated by NO_WAIT, CLEAN_READ, PRIVATE, and no early validation until commit. An approximated 2PL* uses immediate public visibility for writes, committed-only reads, and waiting until dependent transactions commit. IC3- or Callas-like protocols are represented by combinations of early public writes, dirty reads, piece-level waiting, and early validation at boundaries. Polyjuice can therefore emulate familiar algorithms, but its search space also contains hybrid policies that do not correspond to any named protocol (Wang et al., 2021).
The paper also implemented a policy-gradient alternative using softmax-parameterized discrete choices and REINFORCE-like updates, but evolutionary search performed better. On TPC-C with 1 warehouse and 48 threads, the RL policy reached about 178K TPS after about 100 iterations, whereas the EA policy reached about 309K TPS after about 100 iterations. Training cost is nontrivial but bounded: for TPC-C with 1 warehouse and 48 threads, an iteration with 40 policies and 30-second runs takes about 80 seconds, and the reported training regime typically uses about 300 iterations (Wang et al., 2021).
A plausible implication is that Polyjuice’s practicality depends on workloads whose high-contention operating points recur often enough that overnight or background retraining amortizes the search cost.
5. Learned behavior and empirical performance
Polyjuice is evaluated on TPC-C, TPC-E, and a synthetic microbenchmark on a single machine with 2 NUMA nodes, a 56-core Intel Xeon Gold 6238R @ 2.20 GHz, and 188GB RAM per NUMA node. Runs last 30 seconds, each configuration is repeated five times, and the reported result is the median (Wang et al., 2021).
On TPC-C, Polyjuice is compared with Silo, 2PL, IC3, Tebaldi, and simulated CormCC. Under high contention with 2 warehouses and 48 threads, Polyjuice reaches 907K txn/sec, while IC3 and Tebaldi are about 580K, and the paper reports an improvement of about 56% over the best existing algorithm. Over different TPC-C and TPC-E configurations, the overall improvement range over the best existing baseline is 15% to 56%. Gains are largest under moderate to high contention and shrink as contention decreases; at 48 warehouses, Polyjuice converges to an OCC-like policy and remains about 8% slower than Silo because of extra metadata and bookkeeping overhead (Wang et al., 2021).
The factor analysis clarifies where performance comes from. Starting from an OCC-equivalent policy, adding early validation improves throughput by about 70% at 1 warehouse, and adding fine-grained waits increases throughput from 116K to 309K TPS. At 8 warehouses, early validation alone raises throughput from 467K to 1177K TPS, while additional dimensions have smaller marginal effect. This indicates that early validation is critical for reducing wasted work, whereas fine-grained waiting becomes especially important under heavier contention (Wang et al., 2021).
TPC-E highlights a different mechanism. Under high contention induced by Zipf parameter 5 to 6 on SECURITY updates, Polyjuice outperforms the best baseline by 42% to 55%. The paper attributes much of this gain to learned backoff: Silo’s exponential backoff penalizes TRADE_ORDER too heavily, whereas Polyjuice learns that for some transaction types it is better not to increase backoff even under aborts. At 7, Polyjuice achieves about 8 speedup from 1 to 48 threads, compared with about 9 for IC3, 0 for 2PL, and 1 for Silo (Wang et al., 2021).
The TPC-C case study illustrates the system’s most characteristic behavior. In a dependency chain involving NewOrder and Payment, Polyjuice learns to make the WAREHOUSE read in NewOrder dirty but the CUSTOMER read clean. This shortens waits relative to IC3 by allowing Payment to wait only until an earlier STOCK access rather than a later CUSTOMER access, while simultaneously avoiding unnecessary serialization constraints that would arise if all reads were dirty. This mixed policy—dirty and clean reads within the same transaction type, combined with specific wait points—does not correspond to a conventional named protocol (Wang et al., 2021).
6. Robustness, deployment considerations, and relation to other work
Polyjuice policies are workload-specific rather than universal. The paper evaluates generalization by training on one TPC-C configuration and testing on others. Policies perform best when trained on the exact workload; degradation is moderate for nearby workloads but can be severe for distant ones. For example, a policy trained for 1 warehouse and evaluated at 48 warehouses can become significantly suboptimal, reaching 71% of Silo’s performance (Wang et al., 2021).
This workload specificity shapes the deployment model. The paper analyzes an e-commerce trace using a conflict_rate metric computed per hour from overlapping requests on the same product ID. Comparing today’s peak conflict_rate with tomorrow’s peak over 197 days, only 3 days had error greater than 20%, and most days were within 15%. The proposed operational rule is to retrain only when predicted conflict_rate differs by more than 15% from that of the workload on which the current policy was trained; under this rule, only 15 retraining instances were needed over 196 days. Policy switching itself is lightweight: switching from OCC to a 1-warehouse-optimized policy during a TPC-C run takes about 3 seconds for all threads to adopt the new policy, with monotonically improving throughput and no spike in aborts (Wang et al., 2021).
The same evidence also defines the main failure modes. Workloads that change faster than Polyjuice can train are not suitable. If the training workload is unrepresentative, performance may degrade substantially. Because replayed training traces preserve inputs but not exact execution outputs, training may mis-estimate contention patterns when workload behavior is extremely sensitive to returned values and complex data-dependent control flow (Wang et al., 2021).
In relation to prior work, Polyjuice subsumes a broad range of concurrency control designs as points in its policy space. It can encode OCC, approximate 2PL*, and IC3/Callas-style behavior, while differing from MOCC, Sundial, Tebaldi, CormCC, and other adaptive schemes by searching over per-access micro-decisions rather than selecting one protocol per data partition or per transaction type. The framework is also positioned within the broader learned database literature, but unlike learned indexes or learned optimizers, runtime inference is a table lookup rather than a continuous model evaluation, and correctness is preserved by leaving validation outside the learned component (Wang et al., 2021).
A common source of confusion is the name itself. “Polyjuice” also refers to a GPT-2–based counterfactual generator for NLP (Wu et al., 2021); that system is unrelated to concurrency control. In database systems usage, Polyjuice specifically denotes the learned, workload-specialized concurrency control framework introduced in 2021 (Wang et al., 2021).