feat(scheduler-core): implement record start/stop lifecycle (task 9.2)
Adds recording-state fields directly to xce_scheduler_t (no new
xce_sched_driver_t type, per task 9.1's precedent). sched_record_start()/
sched_record_stop() implement AC 10: validate via task 9.1's path
validator, open with a TOCTOU-hardened sequence (O_NOFOLLOW, no O_TRUNC,
fstat()+st_nlink==1 check before ftruncate()), snapshot the core, write
ReplayHeader+SnapshotEntry on start, ReplayEvent{endSession} on stop.
driver.c gains boolean-gated recording hooks in
xce_sched_driver_translate_pending_events() (per-event-batch ReplayEvent
writes, new recording_events.c) and xce_sched_driver_run_normal_mode_round()
(per-session ReplaySession writes, new recording_session.c) -- zero I/O/
allocation when inactive.
Two real bugs found and fixed during implementation: bug-1498 (O_TRUNC
would have truncated a hard-linked victim file before the TOCTOU check
could reject it) and bug-1499 (a transient edit dropped
xce_core_signal_go(), causing a 3-way thread deadlock).
test_record_lifecycle.c decodes the full start->events->session->stop
cycle with the real capnp decoders and asserts the exact message
sequence; TOCTOU regression tests use real symlink(2)/link(2) syscalls.
25/25 scheduler suite, clang-format clean.
This commit is contained in:
parent
4e5547ee55
commit
ff8d4f416e
15 changed files with 2110 additions and 36 deletions
|
|
@ -5,7 +5,9 @@
|
|||
#include <pthread.h>
|
||||
#include <rtti.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "client.h"
|
||||
|
|
@ -117,6 +119,37 @@ typedef struct {
|
|||
* xce_sched_driver_t (record_file_path/record_file/recording/
|
||||
* record_event_count/...) is task 9.2's job, not this field's. */
|
||||
char* record_dir;
|
||||
/* Req 5 AC 10 (scheduler-core spec, task 9.2): the recording lifecycle
|
||||
* state design.md sketches on a future xce_sched_driver_t -- per
|
||||
* record_dir's own comment above, this codebase keeps a single combined
|
||||
* driver-level struct (xce_scheduler_t), so these fields land here
|
||||
* instead of a new type. Owned exclusively by recording.c's
|
||||
* sched_record_start()/sched_record_stop() (recording.h) -- see those
|
||||
* functions' doc comments for the full lifecycle contract (path
|
||||
* validation + TOCTOU-hardened open on start, end-of-recording marker +
|
||||
* flush/close on stop). driver.c's normal-mode loop (driver.h) reads
|
||||
* `recording` to boolean-gate its per-event-batch/per-session recording
|
||||
* writes -- see xce_sched_driver_translate_pending_events()'s and
|
||||
* xce_sched_driver_run_normal_mode_round()'s own comments.
|
||||
*
|
||||
* Invariant: recording == true iff record_file != NULL. */
|
||||
bool recording;
|
||||
/* strdup'd copy of the resolved record file path; owned by the record
|
||||
* file lifecycle (strdup on start, free+NULL on stop or start/write
|
||||
* failure) -- lets a future status query (task 9.4, out of this task's
|
||||
* scope) answer with the current path even after record_file closes. */
|
||||
char* record_file_path;
|
||||
/* replay file handle; NULL when not recording. */
|
||||
FILE* record_file;
|
||||
/* count of ReplayEvent messages written since recording started (used
|
||||
* by task 9.3's periodic-checkpoint trigger; incremented by
|
||||
* recording.c's event-batch writer, task 9.2). */
|
||||
uint64_t record_event_count;
|
||||
/* N events between periodic snapshot checkpoints (0 = disabled).
|
||||
* Reserved for task 9.3 -- inert (never read) as of task 9.2. */
|
||||
uint64_t record_snapshot_interval;
|
||||
/* logical time (xce_core_now()) recording started; 0 = not recording. */
|
||||
uint64_t record_start_ts;
|
||||
} xce_scheduler_t;
|
||||
|
||||
extern int sched_init(xce_scheduler_t*, xce_client_config_t*,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue