Namespace Hi.SqliteUtils
Classes
- NcResultActualTimeAmendment
Internal Use Only. One step's measured time to write onto a completed result file (AmendActualTimes(IEnumerable<NcResultActualTimeAmendment>, CancellationToken)): what the CSV one-to-one mapping set on the step after the play.
- NcResultMeta
Internal Use Only. The
Metarows of a result file as SqliteNcResultReader reads them when it opens the file: what the writer wrote at creation (the schema version, the app version, the NC name, the creation time) and, for a completed file, what it wrote at completion (the counts, whether the play ran to its end, the completion time, thefinish.wctbeside the file and its hash). Finalized is true exactly for a file the writer completed – a single file in rollback-journal mode, with no-walor-shmbeside it. The members written at completion are null for a recording that crashed or was abandoned; a completion that failed after its commit (the checkpoint or the switch out of WAL mode refused by another connection) leaves them set with Finalized false, so Finalized is the one thing to key on. The times are UTC, their Kind Utc. A completed file an amend wrote into afterwards says so in its two stamps (ActualTimesAmendedUtc, BriefsAmendedUtc).
- SqliteIdentityRole
Base class for SQLite-based identity roles.
- SqliteIdentityStorage
SQLite-based storage for ASP.NET Core Identity.
- SqliteIdentityStorage.RoleRow
Represents a role row in the database.
- SqliteIdentityStorage.UserRow
Represents a user row in the database.
- SqliteIdentityUser
Base class for SQLite-based identity users.
- SqliteNcResultAmender
Internal Use Only. The amender of a completed result file (the NC play result recording's P3), opened by OpenWrite(string): it writes onto steps the file holds what two commands write onto the steps after a play – the measured time the CSV one-to-one mapping sets (AmendActualTimes(IEnumerable<NcResultActualTimeAmendment>, CancellationToken)) and the two briefs the step-physics recompute replaces (AmendStepBriefs(IEnumerable<StepBrief>, CancellationToken): the force brief and the sequential physics state both, as the recompute rebuilds the sequential chain of every step it passes). A step's record is taken once by the writer and never added again, so these are the one way a recorded value changes. An amend rewrites whole chunks: the chunk is decoded, the step's payload replaced, the chunk laid out and compressed again and its row updated – one transaction a bin (1,024 steps), the file's rollback journal keeping it consistent – so the amendments are handed in by step index ascending and the cost is a chunk's decode and encode for every bin touched, not for every step. Each amend that wrote something stamps its time into
Meta(ActualTimesAmendedUtc, BriefsAmendedUtc) in the transaction of every bin it wrote, so a bin that stands carries the stamp even when a later bin fails, and a review can tell a file that carries measured times, or recomputed briefs, from one that holds the play's values alone.The file stays completed (
Finalized1, rollback-journal mode); a file that was not completed is refused. The amender wants the file to itself. On Windows a file another connection holds open -- a review, a listing, another program -- is refused when the amender opens (a share-mode probe); other systems do not enforce share modes, so there the open passes, and SQLite's own locks keep each bin's transaction whole: a reader in the middle of a read makes a bin wait up to two seconds, then fail. Neither keeps a reader's chunk cache current: a review reads the chunks as they were when its cache took them, so it is reopened, or its cache dropped, after an amend. Any thread may call the amender, one call at a time.
- SqliteNcResultReader
Internal Use Only. The reader of one result file (the NC play result recording's P2), opened read-only by OpenRead(string): the file's Meta and NC source files, read once; a step's narrow row without its chunk (TryGetStepRow(int, out NcResultStepRow)), a step's whole record (TryGetMachiningStep(int, out MachiningStepRecord)) or a window of them (FindMachiningSteps(int, int, bool)), a step's briefs (TryGetStepBrief(int, out StepBrief), FindStepBriefs(int, int)), the strip positions in order (EnumerateClStripPositions(int, int)), a piece by its id (TryGetSyntaxPiece(int, out SyntaxPieceRecord)), the pieces of a source line by path (FindPieceIds(string, int)) or by file index (FindPieceIds(int, int); FindPieceAddresses(int, int, int) for a range of lines), a step's block text (TryGetStepBlockText(int, out string)), and the finished stock's node map whole (ReadNodeAttachments(), schema version 2).
A record is read by locating its chunk (
StepIndex / 1024for the step-indexed kinds, the index row for a piece) and decompressing the chunk; the reader keeps the last LruChunks decoded chunks of each kind, so a step next to the last one read costs a slice, a step far from it a decompression (a millisecond or so for a step chunk, under a millisecond for a piece chunk). A window of steps or briefs decodes each chunk it crosses once. Everything a call returns is a copy or an object of its own: nothing aliases the reader's buffers. The sentence snapshots of a piece chunk are kept with the chunk and nowhere else, so the records of one piece -- its steps' and its own -- share one snapshot object while the chunk is cached; once the chunk has left the cache, the snapshot is rebuilt as another object, equal in every value it carries. The file path of every snapshot is the one string the reader keeps for that path (the paths of NcFiles first), as a live play's sentences share theirs.A file that was not completed reads as far as it was committed: a step or piece row whose chunk never reached the file reads as no record (TryGetStepRow(int, out NcResultStepRow) true and TryGetMachiningStep(int, out MachiningStepRecord) false, a step's
Sentencenull, a piece absent, a window skipping the chunk). A chunk that is in the file but not a chunk this build reads -- another codec, a layout version, a slot pointing outside its payloads, a payload the wire formats refuse, cut short or with a bad string length -- throws InvalidDataException; a failure of SQLite itself comes out as SqliteException. Any thread may call the reader, one call at a time: every method, Dispose() included, runs under the reader's lock and waits there for a call in progress, and an enumeration of positions holds the lock only while it decodes one chunk. After Dispose(), every method but Dispose() throws ObjectDisposedException, an empty window included (a null path of FindPieceIds(string, int) is refused first), while DatabasePath, Meta and NcFiles stay readable.
- SqliteNcResultStorage
Internal Use Only. The entry to a play's result file (the NC play result recording's P2): one SQLite file a recording, holding the records of the plan's P1 – the machining steps, the strip positions, the executed syntax pieces – and the two briefs of every published step, beside the file's
Meta, the NC source files and the pool of the program-zero matrices. Create(string, string) opens a new file for the recorder to write (SqliteNcResultWriter), OpenRead(string) opens a recorded file for a review to read (SqliteNcResultReader); the constants are the file's identity (ApplicationId, SchemaVersion), its chunking and its table names. The file is recognised by its SQLiteapplication_idand gated by itsuser_version; the step-indexed records live in chunks of StepsPerChunk steps (chunkkholds the stepsk * 1024tok * 1024 + 1023: a record's bin isStepIndex / 1024, its slot its place in the bin), the pieces in chunks of up to PiecesPerChunk pieces closed at PieceChunkRawBytes raw bytes, every chunk Brotli-compressed. Since schema version 2 (the plan's P5) a completed file may also hold the node map of its finished stock: for every strip position the native attachment pointer the stock's nodes carry in thefinish.wct(NodeAttachChunkTableName, 1,024 positions a chunk, written once at the completion), by which a review binds the stock's nodes to its rebuilt positions. Nothing here is shared across instances: no default storage, no pooled connection.A file's life: Create(string, string), the writer's
Add*calls while the play runs, then Complete(bool), which makes it one self-contained file marked Finalized; a writer disposed without completing abandons the file, which stays, not finalized, for the recorder to delete. A reader opens either. A writer and a reader each take calls from any thread, one at a time, on a lock of their own, and their exceptions follow one rule: an argument the file's content refuses is an ArgumentException, thrown before anything is written; a writer or reader past its end (completed, disposed) throws ObjectDisposedException; a file that is not a result file, or a chunk this build does not read, is an InvalidDataException; a completion another connection holds back is an InvalidOperationException; SQLite's own failures come out as SqliteException, after which a writer is to be disposed. These three types and the three row types (NcResultMeta, NcResultSourceFile, NcResultStepRow) are marked for internal use as the contract between the play's recorder, this storage and the review of a play, not an application's API, until a sample reads a result file.
- SqliteNcResultWriter
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.
- SqliteRoleStore<TRole>
SQLite-based role store for ASP.NET Core Identity.
- SqliteStepStorage
The step cache: an SQLite file holding one StepLuggage row a step, a column a kind (StepLuggageTableName), and one
StepBriefrow a published step, a column a brief (StepBriefTableName: the MillingForceBrief and the SeqPhysicsState, the brief-into-DB chain's C3). The play writes whole rows in batches, a step's two rows in one transaction; the step-physics recompute amends what it rewrote, a chunk at a time in one transaction (AmendStepPhysics(IReadOnlyList<StepPhysicsAmendment>): the force column and the briefs' row); every consumer reads what it uses – one kind of one step, one kind over an index range, the whole rows for the recompute and the HardNc NC optimization, the briefs' rows (StepBrief) for the recompute and the NC optimization's solver, or which kinds the rows hold – straight from the file, with no cache in front of it. The step variables written onto the steps (the chain's C4c) are two more tables of the same file: a key table (StepVariableKeyTableName) and a value table, a row a (key, step) (StepVariableTableName); a play's writes land in the consignment's transaction, a mapping's, a training's and a script's batches in one transaction a batch (WriteStepVariables(IReadOnlyList<StepVariableWrite>)), and a reader asks one value of one step, one key over a range, or every key over a range. Two luggage columns are stored in a form of the file's own and decoded back on every read: the no-cut force record as its 8-byte header, the substraction's contours deflated behind the 13-byte header.
- SqliteUserStore<TUser>
SQLite-based user store for ASP.NET Core Identity.
Structs
- NcResultAmendResult
Internal Use Only. What one amend of a result file did (SqliteNcResultAmender): the steps it wrote, counted where each of a step's places was found – a step the file holds may have its narrow row without its step payload, or its step payload without its briefs – and whether it stopped early.
- NcResultPieceAddress
Internal Use Only (the NC play result review). One piece of a result file by its address in a source file, as FindPieceAddresses(int, int, int) answers a range of lines: the piece's id, the 0-based line its sentence begins at, and the sentence's execution-order index (-1 when the piece recorded none).
- NcResultSourceFile
Internal Use Only. One row of a result file's
NcFiletable: an NC source file's index as the sentences of the play carry it, and its path. A file index is allocated by the NC pipeline for every file it enters and for every control-flow jump (a GOTO, a loop, a subprogram or macro call), so one path can have many indices, and a line of one path can map to several pieces: the reader's FindPieceIds(string, int) looks a line up by path. The writer records an index once, with the path of the first piece that carried it.
- NcResultStepRow
Internal Use Only. The narrow row of one machining step in a result file, read without decoding the step's chunk (TryGetStepRow(int, out NcResultStepRow)): the queryable scalars of the step. Everything else of the step – its motion, its removal scalars, its collided pairs, its measured time, the pair on the workpiece geometry coordinate – is in the step's chunk and read by TryGetMachiningStep(int, out MachiningStepRecord). The two nullable columns read -1 for NULL.