Class SqliteNcResultWriter
- Namespace
- Hi.SqliteUtils
- Assembly
- HiNc.dll
Internal Use Only. The writer of one result file (the NC play result recording's P2), opened by Create(string, string): the recorder of the plan's P3 adds the records of a play as they come – a strip position, a published step with the id of its sentence's piece, a step's two briefs, an executed piece with its id – and Complete(bool) turns the file into a single artifact; disposing the writer without completing it abandons the recording (the file stays, not completed, for the recorder to delete). The writer is not the pipeline's sink (it does not implement IMachiningResultSink): it blocks on its own lock and on SQLite, so the recorder keeps the play's threads off it and owns the back-pressure. Any thread may call it, one call at a time: every method, Complete(bool) and Dispose() included, runs under the writer's lock and waits there for a call in progress.
The step-indexed records go into chunks of StepsPerChunk
steps, each kind (positions, steps, briefs, node keys) on its own: a record for a later chunk closes
the open chunk of its kind, so a chunk once closed takes no more records -- a record with
a negative index, for a closed chunk, for a chunk below the open one, or for an index
already stored is refused before a byte is written. Within the open chunk the order is
free; the kinds are not ordered against each other. A step takes one record of each
kind (there is no amend), and the writer knows no runs: a replay that counts its steps
from 0 again goes to a new file. The pieces go into chunks of up to
PiecesPerChunk pieces, closed at
PieceChunkRawBytes raw bytes, in any order of ids.
The file is committed every time a chunk closes (every 1,024 steps of a kind, every 256
pieces or 4 MB of them) and at completion, so a crash loses at most the open chunk of
each kind. The kinds share one batch, so a row of a step or a piece may be committed by
another kind's chunk before its own chunk is; the reader reads such a row as no record.
A commit is not synced to the disk (WAL with synchronous=NORMAL): a power cut may
also lose the commits since the last checkpoint, the file staying consistent.
Exceptions: an argument the file's content refuses -- a null record, a record that breaks the chunk order, a piece id stored before, a record the wire formats refuse (more than six machine coordinates, a null collided pair) -- is an ArgumentException (an ArgumentNullException for a null) thrown before anything of the record is written, and the writer goes on. A SqliteException (the disk full, the file locked, an I/O error), or an InvalidOperationException from a chunk the Brotli encoder refuses, leaves the writer in an unknown state: dispose it. Complete(bool) throws InvalidOperationException when another connection holds the file, the writer then disposed and the file not finalized. After Complete(bool) or Dispose(), every method but Dispose() throws ObjectDisposedException once its arguments pass the checks that need no file (a null record or argument, a brief without its sequential physics state, a hash that is not 32 bytes); DatabasePath stays readable.
public sealed class SqliteNcResultWriter : IDisposable
- Inheritance
-
SqliteNcResultWriter
- Implements
- Inherited Members
- Extension Methods
Properties
DatabasePath
The full path of the result file.
public string DatabasePath { get; }
Property Value
Methods
AddClStripPos(in ClStripPosRecord)
Adds a strip position's record to the position chunk StepIndex / 1024: its program
CL, the point and the normal, as the 48 raw bytes of the dvec3d_t (NaN
payloads and signed zeros kept). A position for a later chunk first closes the open
position chunk and commits the file. Any thread may call it; the calls are serialized on
the writer's lock.
public void AddClStripPos(in ClStripPosRecord pos)
Parameters
posClStripPosRecordThe position's record.
Exceptions
- ArgumentException
The position breaks the chunk order of the positions (a negative index, a closed chunk, a chunk below the open one, an index stored before); nothing is written and the writer goes on.
- ObjectDisposedException
The writer was completed or disposed.
- SqliteException
SQLite failed to write the closing chunk or to commit; the writer is in an unknown state: dispose it.
AddMachiningStep(MachiningStepRecord, int)
Adds a published step's record: its narrow row (the columns of NcResultStepRow
– the id of its sentence's piece and its sentence's index NULL for a step without them –
and the pool ids of its two program-zero matrices) and, in the step chunk
StepIndex / 1024, its other bytes: the pair on the workpiece geometry coordinate
when the motion carries one (a step without one reads back without one), the motion
(WriteBin(BinaryWriter)), the removal scalars, the collided pairs (a null
array as the wire format's 5-byte null record) and the measured time when the step has one
(no bytes at all when it has none). The two matrices of the motion's
ProgramZeroLegs go into the matrix pool, a row a distinct
matrix. A step for a later chunk first closes the open step chunk and commits the file.
Any thread may call it; the calls are serialized on the writer's lock.
public void AddMachiningStep(MachiningStepRecord step, int pieceId)
Parameters
stepMachiningStepRecordThe step's record.
pieceIdintThe id the recorder gave the step's sentence (the piece built from it); below 0 for a step without one, stored as NULL. The writer does not check it against the pieces.
Exceptions
- ArgumentNullException
stepis null.- ArgumentException
The step breaks the chunk order of the steps (a negative index, a closed chunk, a chunk below the open one, a step stored before), or its record cannot be written (more than six machine coordinates, a null collided pair); nothing is written and the writer goes on.
- ObjectDisposedException
The writer was completed or disposed.
- SqliteException
SQLite failed to write the row, a pooled matrix, the closing chunk or the commit; the writer is in an unknown state: dispose it.
AddNodeAttachments(ReadOnlySpan<long>)
Adds the finished stock's node map (schema version 2; the NC play result recording's P5): for every
strip position i, keys[i] is the native attachment pointer the stock's nodes
carry for that position in the finish.wct written at the same moment (the position's
CbtrPickable.NativeAttachmentHandle), as the 8 raw bytes of the long in the node
attachment chunk i / 1024; a 0 is a position without one and leaves its slot empty. Meant to be
called once, at the completion, with the whole strip (the recorder does): the slots follow the chunk order
contract of the other kinds, so a second call for indices at or below a closed chunk is refused. The
count of keys written is the file's NodeAttachCount once completed. Any thread may call it; the
calls are serialized on the writer's lock.
public void AddNodeAttachments(ReadOnlySpan<long> keys)
Parameters
keysReadOnlySpan<long>The node keys by strip position index; 0 for none.
Exceptions
- ArgumentException
A key breaks the chunk order of the node keys (a chunk closed by an earlier call, an index stored before); the keys before it are written and the writer goes on.
- ObjectDisposedException
The writer was completed or disposed.
- SqliteException
SQLite failed to write a closing chunk or to commit; the writer is in an unknown state: dispose it.
AddStepBrief(StepBrief)
Adds a published step's two briefs to the brief chunk StepIndex / 1024: the force
brief's tri-state record (WriteBin(BinaryWriter, MillingForceBrief?);
a null brief, the physics not run on the step, as the 2-byte null record) and the
sequential physics state's record. The recorder takes them off the step's consignment as the play
writes it, or off the step cache (FindStepBriefs(int, int)) at
completion. A step's briefs are recorded once: there is no amend, and a second record for
the step is refused. A brief for a later chunk first closes the open brief chunk and
commits the file. Any thread may call it; the calls are serialized on the writer's lock.
public void AddStepBrief(StepBrief brief)
Parameters
briefStepBriefThe step's briefs: its force brief null for the null record, its sequential physics state not null.
Exceptions
- ArgumentNullException
briefis null.- ArgumentException
The sequential physics state is null, or the step breaks the chunk order of the briefs (a negative index, a closed chunk, a chunk below the open one, a step stored before); nothing is written and the writer goes on.
- ObjectDisposedException
The writer was completed or disposed.
- SqliteException
SQLite failed to write the closing chunk or to commit; the writer is in an unknown state: dispose it.
AddSyntaxPiece(SyntaxPieceRecord, int)
Adds an executed piece's record: its index row – its address (the file and line index
TryGetFileLineIndex(out int, out int) answers, both NULL when it answers
false), its sentence's index and block text, where its entry lies – and, in the open
piece chunk, its entry: the sentence snapshot's record
(WriteBin(BinaryWriter)) followed by the piece's compact JSON (nothing for
a piece without one, whose JsonLen is NULL). A sentence with an address and a file
path adds the file to the NcFile table the first time its file index is seen: the
first path recorded for an index wins. The ids come in any order; the writer does not
check them against the steps'. A piece the open chunk has no room for first closes it and
commits the file, and the chunk's 256th piece, or its 4 MB, closes it after the append.
Any thread may call it; the calls are serialized on the writer's lock.
public void AddSyntaxPiece(SyntaxPieceRecord piece, int pieceId)
Parameters
pieceSyntaxPieceRecordThe piece's record.
pieceIdintThe id the recorder gave the piece: the key of its row, unique in the file.
Exceptions
- ArgumentNullException
pieceis null.- ArgumentException
A piece with
pieceIdwas stored before: refused at its index row, before its entry reaches the chunk, so the piece leaves nothing in the file (a chunk closed to make room for it stays closed) and the writer goes on.- ObjectDisposedException
The writer was completed or disposed.
- SqliteException
SQLite failed to write the rows, the closing chunk or the commit; the writer is in an unknown state: dispose it.
Complete(bool)
Completes the file without a finish.wct: see Complete(bool, string, byte[]).
A play the user stopped is completed too, with playCompleted false, when
its file is to stay reviewable; disposing the writer abandons the file.
public void Complete(bool playCompleted)
Parameters
playCompletedboolWhether the play ran to its end (true) or was stopped (false), for the file's
Meta.
Exceptions
- InvalidOperationException
Another connection holds the file, so it could not be checkpointed (a connection in a read transaction) or taken out of WAL mode (a connection that merely has it open; the switch is retried for about two seconds, not the driver's 30), or the Brotli encoder refused a chunk; the writer is disposed and the file left not finalized.
- SqliteException
SQLite failed to write a chunk or the
Metarows, or to commit; the writer is disposed and the file left not finalized.- ObjectDisposedException
The writer was completed or disposed.
Complete(bool, string, byte[])
Completes the file: closes the open chunks of the five kinds, writes the counts of the
records the writer took, whether the play ran to its end, the completion time and the
.wct reference to Meta, commits, checkpoints the WAL and takes the file out
of WAL mode, and only then marks it Finalized – so a file marked completed is one
file in rollback-journal mode that needs no -wal or -shm beside it (those
left are deleted where they can be) and can be copied as it is. No other connection, of
this process or another, may hold the file meanwhile. Past its argument checks the call
disposes the writer, successfully or not. A failure leaves the file not finalized, with
what the call had committed: a refused checkpoint or switch leaves the counts, the
completion time and the .wct reference in Meta, the file in WAL mode.
public void Complete(bool playCompleted, string wctRelPath, byte[] wctSha256)
Parameters
playCompletedboolWhether the play ran to its end (true) or was stopped (false), for the file's
Meta.wctRelPathstringThe path of the
finish.wctrelative to the file; not null.wctSha256byte[]The SHA-256 of that
.wct, 32 bytes, stored as lower-case hex; not null.
Exceptions
- ArgumentNullException
wctRelPathorwctSha256is null; the writer is left as it was.- ArgumentException
wctSha256is not 32 bytes; the writer is left as it was.- InvalidOperationException
Another connection holds the file, so it could not be checkpointed (a connection in a read transaction) or taken out of WAL mode (a connection that merely has it open; the switch is retried for about two seconds, not the driver's 30), or the Brotli encoder refused a chunk; the writer is disposed and the file left not finalized.
- SqliteException
SQLite failed to write a chunk or the
Metarows, or to commit; the writer is disposed and the file left not finalized.- ObjectDisposedException
The writer was completed or disposed.
Dispose()
Closes the writer. Without Complete(bool) before it this abandons the
recording: the open batch is rolled back (the open chunks are lost, with the rows written
since the last commit), the file stays where it is, not completed – Finalized 0,
as Create(string, string) wrote it – for the recorder to delete. A
play whose file is to stay reviewable is completed instead. Idempotent, and a no-op after
Complete(bool); it waits for a call in progress on another thread.
public void Dispose()