Class JsonIdentity
Commit gate. A commit holds the gate's read side from allocating its record's sequence number until its changes are in the operators' committed entries; a write outside a transaction holds it while it applies. A checkpoint takes the write side only to capture the dirty entries and allocate its own number, so every commit numbered below the checkpoint is fully applied before the capture and every other commit is numbered above it.
Checkpoint. checkpoint() writes every entry changed since the last checkpoint, of
every operator of the identity, to its file through one checkpoint record, then truncates the
journal. Checkpoints of one identity run one at a time, from capture to clearing the dirty marks.
Recovery. recoverOnce() replays the identity's committed records into its table
files before any of its tables is read. Success is remembered; a refusal (a damaged record, an
unreadable file) is not, so the next request for one of the identity's operators runs recovery
again, for example after the server operator has moved a damaged record aside.
Internal to the JSON backend. Public only because JsonTransactionManager, in another
package, holds one; not part of the supported API.
- Since:
- 6.3.0
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescription(package private) static final classOne dirty key captured by a checkpoint: its generation and its committed value, ornullif deleted.(package private) static interfaceA test callback for the named checkpoint steps. -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final ReentrantLockHeld by a checkpoint from its capture until its dirty marks are cleared: one checkpoint at a time.private final ReentrantReadWriteLockSee the class javadoc.private final AtomicLongSource of dirty-mark generations; a mark's generation changes whenever its key is written again.private final JsonJournalprivate final StringThe identity's name, used only in messages.private static final JsonIdentity.StepHookprivate final List<SimpleJsonDataOperator<?>> The identity's operators, in registration order.private booleanWhetherrecoverOnce()has succeeded; guarded bythis.(package private) static final StringFired after a checkpoint's capture and number allocation, with the gate released, before its record is written.(package private) static final StringFired after a checkpoint's truncation, before its dirty marks are cleared.private static JsonIdentity.StepHookTest seam: called with a step name at the points named above. -
Constructor Summary
ConstructorsModifierConstructorDescriptionprivateJsonIdentity(String name, Path root, Path journalDirectory) -
Method Summary
Modifier and TypeMethodDescription(package private) static JsonIdentityThe identity of a plugin or an external data folder: its tables are the sub-directories ofroot, and its journal is<root>/.ultitools-journal.(package private) voidWrites every entry changed since the last checkpoint to its file, crash atomically, and truncates the journal (20.4-RESEARCH.md section 12.7).(package private) ReentrantLock(package private) ReentrantReadWriteLockprivate List<JsonJournal.Entry> entriesOf(List<JsonIdentity.Captured> captured) (package private) static void(package private) static JsonIdentityforStandaloneTable(String tableDirectory) The identity of one directly constructed operator: its table directory's parent is the root, and its journal is<table dir>.ultitools-journal, a sibling of the table directory, so the table directory never holds a journal file.(package private) static void(package private) JsonJournaljournal()name()The identity's name, for messages.(package private) longA generation no dirty mark of this identity has carried before.(package private) List<SimpleJsonDataOperator<?>> (package private) voidBrings the identity's table files to the state of its committed journal records, once.(package private) voidregister(SimpleJsonDataOperator<?> operator) Addsoperatorto the operators a checkpoint captures.(package private) static void(package private) StringThe name a journal record givestableDirectory: its path relative to the identity root.
-
Field Details
-
STEP_CHECKPOINT_CAPTURED
Fired after a checkpoint's capture and number allocation, with the gate released, before its record is written.- See Also:
-
STEP_CHECKPOINT_TRUNCATED
Fired after a checkpoint's truncation, before its dirty marks are cleared.- See Also:
-
NO_STEP_HOOK
-
stepHook
Test seam: called with a step name at the points named above. A no-op in production; a test installs a callback that pauses or fails at one step and resets it afterwards. -
name
The identity's name, used only in messages. -
journal
-
commitGate
See the class javadoc. Lock order: table locks, then this, then the visibility lock. -
checkpointMutex
Held by a checkpoint from its capture until its dirty marks are cleared: one checkpoint at a time. -
operators
The identity's operators, in registration order. -
generations
Source of dirty-mark generations; a mark's generation changes whenever its key is written again. -
recovered
private boolean recoveredWhetherrecoverOnce()has succeeded; guarded bythis.
-
-
Constructor Details
-
JsonIdentity
-
-
Method Details
-
atRoot
The identity of a plugin or an external data folder: its tables are the sub-directories ofroot, and its journal is<root>/.ultitools-journal.- Parameters:
name- the identity's name, for messagesroot- the directory whose sub-directories are the identity's tables- Returns:
- the identity
-
forStandaloneTable
The identity of one directly constructed operator: its table directory's parent is the root, and its journal is<table dir>.ultitools-journal, a sibling of the table directory, so the table directory never holds a journal file.- Parameters:
tableDirectory- the operator's table directory- Returns:
- the identity
-
name
The identity's name, for messages.- Returns:
- the plugin name, data-folder path or table directory this identity stands for
-
journal
JsonJournal journal() -
commitGate
ReentrantReadWriteLock commitGate() -
checkpointMutex
ReentrantLock checkpointMutex() -
tableName
The name a journal record givestableDirectory: its path relative to the identity root. A table directory that is not a direct child of the root gives a name the journal refuses, so a record can never write outside the table's own directory. -
register
Addsoperatorto the operators a checkpoint captures. -
operators
List<SimpleJsonDataOperator<?>> operators() -
nextGeneration
long nextGeneration()A generation no dirty mark of this identity has carried before. -
recoverOnce
void recoverOnce()Brings the identity's table files to the state of its committed journal records, once. Called before any of the identity's tables is read. Success is remembered; a refusal is not, so the next call runs recovery again.- Throws:
DataAccessException- naming the file if a committed record is damaged (DATA_INTEGRITY_VIOLATION, question 8 option A), naming the file, table and id if a committed record holds an id this file system cannot name (DATA_PERSISTENCE_FAILED, question 12 option A), orDATA_PERSISTENCE_FAILEDif a journal or table file cannot be read, written or deleted, or a table or journal directory cannot be forced to disk; either way the identity stays closed and the next request runs recovery again
-
checkpoint
void checkpoint()Writes every entry changed since the last checkpoint to its file, crash atomically, and truncates the journal (20.4-RESEARCH.md section 12.7). In order:- take the checkpoint mutex, so checkpoints of this identity run one at a time, waiting for one already running;
- under the commit gate's write side, capture every dirty key of every operator with its generation and its committed value or absence, and allocate the checkpoint's sequence number K; nothing captured: return without writing anything;
- write checkpoint record K, then the captured entity files (deleting those of deleted
entries), force the table directories, and delete every record numbered up to K in
ascending order, K last (
JsonJournal.checkpoint(long, List)); - clear each captured dirty mark whose generation is unchanged, so a key written again after the capture stays dirty for the next checkpoint.
- Throws:
DataAccessException- (DATA_PERSISTENCE_FAILED) if a record or entity file cannot be written, moved or deleted, or a journal or table directory cannot be forced to disk; the dirty marks stay, so the next checkpoint writes the same entries again
-
entriesOf
-
installStepHook
-
resetStepHook
static void resetStepHook() -
fire
-