An Accumulator accumulates statistical information in the MVCC Transaction environment without creating write-write dependency conflicts. Subclasses include SumAccumulator
, MinAccumulator
, MaxAccumulator
and SeqAccumulator
which compute the sum, minimum and maximum values of contributions by individual transactions. (See below for semantics of the SeqAccummulator
.) Each contribution is accounted for separately as a Delta
instance until the transaction is either committed or aborted and there are no other concurrently executing transactions that started before the commit timestamp. This mechanism is designed to provide a "snapshot" view of the Accumulator that is consistent with the snapshot view of the database.
In more detail: each type of Accumulator has an update method that may only be invoked within the scope of a transaction T. That update is not visible to any other transaction until T commits. Moreover, any other concurrently executing transaction having a start timestamp less than T's commit timestamp does not see the results of the update. To accomplish this, the state of the Accumulator visible within a transaction is computed by determining which updates are visible and aggregating them on demand.
The updates invoked on committed Transactions are recorded in the Journal and reapplied during recovery to reproduce an accurate version of the Accumulator state when Persistit starts up. There can be at most 64 Accumulators per Tree. A snapshot value of each Accumulator is stored once per checkpoint. Checkpoint snapshot values are held in the directory tree of the volume containing the Tree.
Types of Accumulators
The following defines intended use cases for the various types of accumulators:
- {@link com.persistit.Accumulator.Type#SUM}
- Row count, total size, sums of various other characteristics
- {@link com.persistit.Accumulator.Type#MAX}
- Maximum value
- {@link com.persistit.Accumulator.Type#MIN}
- Minimum value
- {@link com.persistit.Accumulator.Type#SEQ}
- Sequence number generation, e.g., auto-increment or internal primary key assignment
Snapshot and Live Values
Each Accumulator type supplies both a "snapshot" value and a "live" value. The snapshot value is computed as described above by selectively applying only those updates visible to the transaction. The live value, however, is simply the result of applying each update operation atomically to a long value maintained by the Accumulator. For example, if ten transactions increment a SUM accumulator by one, and then five commit of them and five and roll back, the live value is nonetheless increased by ten. Thus the live value is only an estimate. Its value is cheap to acquire but not transactionally accurate.
SeqAccumulator
The
SeqAccumulator
is a combination of
SumAccumulator
and
MaxAccumulator
. When the {@link com.persistit.Accumulator.SeqAccumulator#allocate()} method is called,the Accumulator's
live
value is atomically incremented and the resulting value is returned. In addition, a
Delta
holding the resulting sum as a proposed minimum value is added to the transaction. These semantics guarantee that every value returned by a SeqAccumulator (within a transaction that actually commits) is unique, and that upon recovery after a normal shutdown or crash, the first value returned will be larger than the maximum value assigned by any transaction that committed successfully before the shutdown. Note that a transaction that allocates a value and then aborts leaves a gap in the numerical sequence.
@author peter