diff --git a/include/amduat/asl/asl_store_index_fs.h b/include/amduat/asl/asl_store_index_fs.h index 1b19028..d00c20a 100644 --- a/include/amduat/asl/asl_store_index_fs.h +++ b/include/amduat/asl/asl_store_index_fs.h @@ -43,6 +43,10 @@ typedef struct { uint64_t last_ingest_time_ns; amduat_asl_snapshot_id_t next_snapshot_id; bool snapshot_state_initialized; + bool log_tail_initialized; + uint64_t log_tail_logseq; + uint8_t log_tail_hash[32]; + bool skip_exists_precheck; void *open_segments; pthread_mutex_t write_mutex; uint32_t write_depth; diff --git a/src/adapters/asl_store_index_fs/asl_store_index_fs.c b/src/adapters/asl_store_index_fs/asl_store_index_fs.c index bcf2114..7a969df 100644 --- a/src/adapters/asl_store_index_fs/asl_store_index_fs.c +++ b/src/adapters/asl_store_index_fs/asl_store_index_fs.c @@ -138,6 +138,19 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_impl( amduat_reference_t *out_ref, amduat_asl_index_state_t *out_state); +static bool amduat_asl_store_index_fs_env_truthy(const char *value) { + if (value == NULL || value[0] == '\0') { + return false; + } + if (strcmp(value, "1") == 0 || strcmp(value, "true") == 0 || + strcmp(value, "TRUE") == 0 || strcmp(value, "yes") == 0 || + strcmp(value, "YES") == 0 || strcmp(value, "on") == 0 || + strcmp(value, "ON") == 0) { + return true; + } + return false; +} + static int amduat_asl_store_index_fs_lockfile_acquire( amduat_asl_store_index_fs_t *fs) { char lock_path[AMDUAT_ASL_STORE_INDEX_FS_ROOT_MAX + 32]; @@ -194,6 +207,8 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_begin_write( return AMDUAT_ASL_STORE_ERR_IO; } fs->write_lock_fd = lock_fd; + /* Another store instance may have appended while we were unlocked. */ + fs->log_tail_initialized = false; } fs->write_depth += 1u; return AMDUAT_ASL_STORE_OK; @@ -1193,28 +1208,6 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_load_log( return AMDUAT_ASL_STORE_OK; } -static amduat_asl_store_error_t amduat_asl_store_index_fs_write_log( - const char *log_path, - const char *log_dir, - amduat_asl_log_record_t *records, - size_t record_count) { - amduat_octets_t log_bytes; - amduat_asl_store_index_fs_write_status_t status; - - if (!amduat_enc_asl_log_encode_v1(records, record_count, &log_bytes)) { - return AMDUAT_ASL_STORE_ERR_IO; - } - - status = amduat_asl_store_index_fs_write_replace(log_dir, log_path, - log_bytes.data, - log_bytes.len); - amduat_octets_free(&log_bytes); - if (status == AMDUAT_ASL_STORE_INDEX_FS_WRITE_OK) { - return AMDUAT_ASL_STORE_OK; - } - return AMDUAT_ASL_STORE_ERR_IO; -} - static bool amduat_asl_store_index_fs_encode_artifact_ref( amduat_reference_t ref, uint8_t *out, @@ -1250,6 +1243,240 @@ static bool amduat_asl_store_index_fs_encode_artifact_ref( return true; } +static amduat_asl_store_error_t amduat_asl_store_index_fs_load_log_tail( + const char *log_path, + uint64_t *out_last_logseq, + uint8_t out_last_hash[AMDUAT_ASL_STORE_INDEX_FS_LOG_HASH_LEN]) { + int fd; + uint8_t *header_bytes = NULL; + size_t header_size = 0u; + uint64_t last_logseq = 0u; + uint8_t prev_hash[AMDUAT_ASL_STORE_INDEX_FS_LOG_HASH_LEN]; + bool seen_record = false; + + if (log_path == NULL || out_last_logseq == NULL || out_last_hash == NULL) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + memset(prev_hash, 0, sizeof(prev_hash)); + fd = open(log_path, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT || errno == ENOTDIR) { + *out_last_logseq = 0u; + memcpy(out_last_hash, prev_hash, sizeof(prev_hash)); + return AMDUAT_ASL_STORE_OK; + } + return AMDUAT_ASL_STORE_ERR_IO; + } + + if (!amduat_asl_store_index_fs_log_read_header_bytes(fd, + &header_bytes, + &header_size)) { + close(fd); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + free(header_bytes); + (void)header_size; + + while (true) { + uint8_t record_header[16]; + uint64_t logseq; + uint32_t record_type; + uint32_t payload_len; + uint8_t *payload = NULL; + uint8_t record_hash[AMDUAT_ASL_STORE_INDEX_FS_LOG_HASH_LEN]; + uint8_t expected_hash[AMDUAT_ASL_STORE_INDEX_FS_LOG_HASH_LEN]; + int rc; + + rc = amduat_asl_store_index_fs_log_read_exact_eof(fd, + record_header, + sizeof(record_header)); + if (rc == 0) { + break; + } + if (rc < 0) { + close(fd); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + logseq = amduat_asl_store_index_fs_load_u64_le(record_header); + if (seen_record && logseq <= last_logseq) { + close(fd); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + record_type = + amduat_asl_store_index_fs_log_load_u32_le(record_header + 8u); + payload_len = + amduat_asl_store_index_fs_log_load_u32_le(record_header + 12u); + + if (payload_len != 0u) { + payload = (uint8_t *)malloc(payload_len); + if (payload == NULL) { + close(fd); + return AMDUAT_ASL_STORE_ERR_IO; + } + if (!amduat_asl_store_index_fs_log_read_exact(fd, + payload, + payload_len)) { + free(payload); + close(fd); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + } + + if (!amduat_asl_store_index_fs_log_read_exact(fd, + record_hash, + sizeof(record_hash))) { + free(payload); + close(fd); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + if (!amduat_asl_store_index_fs_log_hash_record(prev_hash, + logseq, + record_type, + payload_len, + payload, + expected_hash) || + memcmp(expected_hash, record_hash, sizeof(record_hash)) != 0) { + free(payload); + close(fd); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + memcpy(prev_hash, record_hash, sizeof(prev_hash)); + last_logseq = logseq; + seen_record = true; + free(payload); + } + + close(fd); + *out_last_logseq = last_logseq; + memcpy(out_last_hash, prev_hash, sizeof(prev_hash)); + return AMDUAT_ASL_STORE_OK; +} + +static amduat_asl_store_error_t amduat_asl_store_index_fs_append_log_record_file( + const char *index_path, + const char *log_path, + uint64_t prev_logseq, + const uint8_t prev_hash[AMDUAT_ASL_STORE_INDEX_FS_LOG_HASH_LEN], + uint32_t record_type, + const uint8_t *payload, + size_t payload_len, + uint64_t *out_new_logseq, + uint8_t out_new_hash[AMDUAT_ASL_STORE_INDEX_FS_LOG_HASH_LEN]) { + int fd = -1; + struct stat st; + bool needs_header = false; + uint8_t *header_bytes = NULL; + size_t header_size = 0u; + uint8_t record_header[16]; + uint8_t record_hash[AMDUAT_ASL_STORE_INDEX_FS_LOG_HASH_LEN]; + uint64_t new_logseq; + + if (index_path == NULL || log_path == NULL || prev_hash == NULL || + out_new_logseq == NULL || out_new_hash == NULL) { + return AMDUAT_ASL_STORE_ERR_IO; + } + if (payload_len != 0u && payload == NULL) { + return AMDUAT_ASL_STORE_ERR_IO; + } + if (payload_len > UINT32_MAX || prev_logseq == UINT64_MAX) { + return AMDUAT_ASL_STORE_ERR_UNSUPPORTED; + } + + new_logseq = prev_logseq + 1u; + + fd = open(log_path, O_RDWR | O_CREAT, 0644); + if (fd < 0) { + return AMDUAT_ASL_STORE_ERR_IO; + } + if (fstat(fd, &st) != 0) { + close(fd); + return AMDUAT_ASL_STORE_ERR_IO; + } + needs_header = st.st_size == 0; + if (!needs_header) { + if (lseek(fd, 0, SEEK_SET) < 0) { + close(fd); + return AMDUAT_ASL_STORE_ERR_IO; + } + if (!amduat_asl_store_index_fs_log_read_header_bytes(fd, + &header_bytes, + &header_size)) { + close(fd); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + free(header_bytes); + (void)header_size; + } + if (lseek(fd, 0, SEEK_END) < 0) { + close(fd); + return AMDUAT_ASL_STORE_ERR_IO; + } + if (needs_header) { + uint8_t header[AMDUAT_ASL_STORE_INDEX_FS_LOG_HEADER_LEN]; + memcpy(header, + k_amduat_asl_store_index_fs_log_magic, + AMDUAT_ASL_STORE_INDEX_FS_LOG_MAGIC_LEN); + amduat_asl_store_index_fs_log_store_u32_le( + header + AMDUAT_ASL_STORE_INDEX_FS_LOG_MAGIC_LEN, + AMDUAT_ASL_STORE_INDEX_FS_LOG_VERSION); + amduat_asl_store_index_fs_log_store_u32_le( + header + AMDUAT_ASL_STORE_INDEX_FS_LOG_MAGIC_LEN + 4u, + AMDUAT_ASL_STORE_INDEX_FS_LOG_HEADER_LEN); + amduat_asl_store_index_fs_log_store_u64_le( + header + AMDUAT_ASL_STORE_INDEX_FS_LOG_MAGIC_LEN + 8u, + 0u); + if (!amduat_asl_store_index_fs_log_write_exact(fd, header, sizeof(header))) { + close(fd); + return AMDUAT_ASL_STORE_ERR_IO; + } + } + + if (!amduat_asl_store_index_fs_log_hash_record(prev_hash, + new_logseq, + record_type, + (uint32_t)payload_len, + payload, + record_hash)) { + close(fd); + return AMDUAT_ASL_STORE_ERR_IO; + } + + amduat_asl_store_index_fs_log_store_u64_le(record_header, new_logseq); + amduat_asl_store_index_fs_log_store_u32_le(record_header + 8u, record_type); + amduat_asl_store_index_fs_log_store_u32_le(record_header + 12u, + (uint32_t)payload_len); + if (!amduat_asl_store_index_fs_log_write_exact(fd, + record_header, + sizeof(record_header)) || + (payload_len != 0u && + !amduat_asl_store_index_fs_log_write_exact(fd, payload, payload_len)) || + !amduat_asl_store_index_fs_log_write_exact(fd, + record_hash, + sizeof(record_hash))) { + close(fd); + return AMDUAT_ASL_STORE_ERR_IO; + } + + if (fsync(fd) != 0) { + close(fd); + return AMDUAT_ASL_STORE_ERR_IO; + } + if (close(fd) != 0) { + return AMDUAT_ASL_STORE_ERR_IO; + } + if (!amduat_asl_store_index_fs_fsync_directory(index_path)) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + *out_new_logseq = new_logseq; + memcpy(out_new_hash, record_hash, sizeof(record_hash)); + return AMDUAT_ASL_STORE_OK; +} + static amduat_asl_store_error_t amduat_asl_store_index_fs_append_log_record_unlocked( amduat_asl_store_index_fs_t *fs, uint32_t record_type, @@ -1258,11 +1485,8 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_append_log_record_unlo amduat_asl_index_state_t *out_state) { char *index_path = NULL; char *log_path = NULL; - amduat_asl_log_record_t *log_records = NULL; - size_t log_count = 0u; - amduat_asl_log_record_t *next = NULL; - uint64_t new_logseq; - uint8_t *payload_copy = NULL; + uint64_t new_logseq = 0u; + uint8_t new_hash[AMDUAT_ASL_STORE_INDEX_FS_LOG_HASH_LEN]; amduat_asl_store_error_t err; if (fs == NULL) { @@ -1287,74 +1511,38 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_append_log_record_unlo return AMDUAT_ASL_STORE_ERR_IO; } - err = amduat_asl_store_index_fs_load_log(log_path, &log_records, &log_count); - if (err != AMDUAT_ASL_STORE_OK) { - amduat_asl_store_index_fs_log_free(log_records, log_count); - free(log_path); - free(index_path); - return err; - } - if (log_count != 0u && log_records == NULL) { - free(log_path); - free(index_path); - return AMDUAT_ASL_STORE_ERR_IO; - } - - if (log_count == 0u) { - log_records = (amduat_asl_log_record_t *)calloc(1u, - sizeof(*log_records)); - if (log_records == NULL) { + if (!fs->log_tail_initialized) { + err = amduat_asl_store_index_fs_load_log_tail(log_path, + &fs->log_tail_logseq, + fs->log_tail_hash); + if (err != AMDUAT_ASL_STORE_OK) { free(log_path); free(index_path); - return AMDUAT_ASL_STORE_ERR_IO; + return err; } - new_logseq = 1u; - } else { - if (log_records[log_count - 1u].logseq == UINT64_MAX) { - amduat_asl_store_index_fs_log_free(log_records, log_count); - free(log_path); - free(index_path); - return AMDUAT_ASL_STORE_ERR_IO; - } - new_logseq = log_records[log_count - 1u].logseq + 1u; - next = (amduat_asl_log_record_t *)realloc( - log_records, (log_count + 1u) * sizeof(*log_records)); - if (next == NULL) { - amduat_asl_store_index_fs_log_free(log_records, log_count); - free(log_path); - free(index_path); - return AMDUAT_ASL_STORE_ERR_IO; - } - log_records = next; + fs->log_tail_initialized = true; } - if (payload_len != 0u) { - payload_copy = (uint8_t *)malloc(payload_len); - if (payload_copy == NULL) { - amduat_asl_store_index_fs_log_free(log_records, log_count); - free(log_path); - free(index_path); - return AMDUAT_ASL_STORE_ERR_IO; - } - memcpy(payload_copy, payload, payload_len); - } - - log_records[log_count].logseq = new_logseq; - log_records[log_count].record_type = record_type; - log_records[log_count].payload = amduat_octets(payload_copy, payload_len); - memset(log_records[log_count].record_hash, 0, - sizeof(log_records[log_count].record_hash)); - log_count += 1u; - - err = amduat_asl_store_index_fs_write_log(log_path, index_path, - log_records, log_count); - amduat_asl_store_index_fs_log_free(log_records, log_count); + err = amduat_asl_store_index_fs_append_log_record_file( + index_path, + log_path, + fs->log_tail_logseq, + fs->log_tail_hash, + record_type, + payload, + payload_len, + &new_logseq, + new_hash); free(log_path); free(index_path); if (err != AMDUAT_ASL_STORE_OK) { return err; } + fs->log_tail_logseq = new_logseq; + memcpy(fs->log_tail_hash, new_hash, sizeof(new_hash)); + fs->log_tail_initialized = true; + if (out_state != NULL && !amduat_asl_store_index_fs_current_state_impl(fs, out_state)) { return AMDUAT_ASL_STORE_ERR_IO; @@ -4114,6 +4302,7 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i amduat_reference_t derived_ref; amduat_octets_t artifact_bytes; amduat_asl_index_state_t current_state; + bool has_current_state = false; amduat_artifact_t existing_artifact; amduat_asl_store_error_t err; char *index_path; @@ -4121,7 +4310,6 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i char *blocks_path; char *segment_path; char *block_path; - char *log_path; uint16_t shard_id; uint64_t segment_id; uint64_t local_segment_id; @@ -4130,11 +4318,8 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i amduat_asl_extent_record_t extent; amduat_octets_t segment_bytes; uint8_t segment_hash[AMDUAT_ASL_STORE_INDEX_FS_SEGMENT_HASH_LEN]; - amduat_asl_log_record_t *log_records; - size_t log_count; uint8_t *seal_payload; size_t seal_len; - uint64_t new_logseq; amduat_asl_store_index_fs_write_status_t write_status; size_t artifact_len; @@ -4163,29 +4348,32 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i fs->shard_count); } - if (!amduat_asl_store_index_fs_current_state_impl(ctx, ¤t_state)) { - amduat_reference_free(&derived_ref); - amduat_octets_free(&artifact_bytes); - return AMDUAT_ASL_STORE_ERR_IO; - } + if (!fs->skip_exists_precheck) { + if (!amduat_asl_store_index_fs_current_state_impl(ctx, ¤t_state)) { + amduat_reference_free(&derived_ref); + amduat_octets_free(&artifact_bytes); + return AMDUAT_ASL_STORE_ERR_IO; + } + has_current_state = true; - existing_artifact = amduat_artifact(amduat_octets(NULL, 0u)); - err = amduat_asl_store_index_fs_get_indexed_impl(ctx, derived_ref, - current_state, - &existing_artifact); - if (err == AMDUAT_ASL_STORE_OK) { - amduat_artifact_free(&existing_artifact); - *out_ref = derived_ref; - amduat_asl_store_index_fs_fill_index_state(out_state, - current_state.snapshot_id, - current_state.log_position); - amduat_octets_free(&artifact_bytes); - return AMDUAT_ASL_STORE_OK; - } - if (err != AMDUAT_ASL_STORE_ERR_NOT_FOUND) { - amduat_reference_free(&derived_ref); - amduat_octets_free(&artifact_bytes); - return err; + existing_artifact = amduat_artifact(amduat_octets(NULL, 0u)); + err = amduat_asl_store_index_fs_get_indexed_impl(ctx, derived_ref, + current_state, + &existing_artifact); + if (err == AMDUAT_ASL_STORE_OK) { + amduat_artifact_free(&existing_artifact); + *out_ref = derived_ref; + amduat_asl_store_index_fs_fill_index_state(out_state, + current_state.snapshot_id, + current_state.log_position); + amduat_octets_free(&artifact_bytes); + return AMDUAT_ASL_STORE_OK; + } + if (err != AMDUAT_ASL_STORE_ERR_NOT_FOUND) { + amduat_reference_free(&derived_ref); + amduat_octets_free(&artifact_bytes); + return err; + } } if (fs->segment_policy.small_artifact_threshold != 0u && @@ -4205,6 +4393,12 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i amduat_asl_store_index_fs_open_segment_contains(open_segment, derived_ref)) { *out_ref = derived_ref; + if (!has_current_state && + !amduat_asl_store_index_fs_current_state_impl(ctx, ¤t_state)) { + amduat_octets_free(&artifact_bytes); + return AMDUAT_ASL_STORE_ERR_IO; + } + has_current_state = true; amduat_asl_store_index_fs_fill_index_state(out_state, current_state.snapshot_id, current_state.log_position); @@ -4254,6 +4448,13 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i return err; } } else { + if (!has_current_state && + !amduat_asl_store_index_fs_current_state_impl(ctx, ¤t_state)) { + amduat_reference_free(&derived_ref); + amduat_octets_free(&artifact_bytes); + return AMDUAT_ASL_STORE_ERR_IO; + } + has_current_state = true; amduat_asl_store_index_fs_fill_index_state(out_state, current_state.snapshot_id, current_state.log_position); @@ -4470,75 +4671,11 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i return AMDUAT_ASL_STORE_ERR_IO; } - if (!amduat_asl_store_index_fs_layout_build_log_path(fs->root_path, - &log_path)) { - amduat_reference_free(&derived_ref); - amduat_octets_free(&artifact_bytes); - free(index_path); - free(segments_path); - free(blocks_path); - return AMDUAT_ASL_STORE_ERR_IO; - } - - log_records = NULL; - log_count = 0u; - err = amduat_asl_store_index_fs_load_log(log_path, &log_records, &log_count); - if (err != AMDUAT_ASL_STORE_OK) { - amduat_reference_free(&derived_ref); - amduat_octets_free(&artifact_bytes); - amduat_asl_store_index_fs_log_free(log_records, log_count); - free(log_path); - free(index_path); - free(segments_path); - free(blocks_path); - return err; - } - - if (log_count != 0u && log_records == NULL) { - amduat_reference_free(&derived_ref); - amduat_octets_free(&artifact_bytes); - free(log_path); - free(index_path); - free(segments_path); - free(blocks_path); - return AMDUAT_ASL_STORE_ERR_IO; - } - - if (log_count == 0u) { - log_records = (amduat_asl_log_record_t *)calloc(1u, - sizeof(*log_records)); - if (log_records == NULL) { - amduat_reference_free(&derived_ref); - amduat_octets_free(&artifact_bytes); - free(log_path); - free(index_path); - free(segments_path); - free(blocks_path); - return AMDUAT_ASL_STORE_ERR_IO; - } - } else { - amduat_asl_log_record_t *next = (amduat_asl_log_record_t *)realloc( - log_records, (log_count + 1u) * sizeof(*log_records)); - if (next == NULL) { - amduat_reference_free(&derived_ref); - amduat_octets_free(&artifact_bytes); - amduat_enc_asl_log_free(log_records, log_count); - free(log_path); - free(index_path); - free(segments_path); - free(blocks_path); - return AMDUAT_ASL_STORE_ERR_IO; - } - log_records = next; - } - seal_len = 8u + AMDUAT_ASL_STORE_INDEX_FS_SEGMENT_HASH_LEN; seal_payload = (uint8_t *)malloc(seal_len); if (seal_payload == NULL) { amduat_reference_free(&derived_ref); amduat_octets_free(&artifact_bytes); - amduat_asl_store_index_fs_log_free(log_records, log_count); - free(log_path); free(index_path); free(segments_path); free(blocks_path); @@ -4554,34 +4691,13 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i seal_payload[6] = (uint8_t)((segment_id >> 48) & 0xffu); seal_payload[7] = (uint8_t)((segment_id >> 56) & 0xffu); memcpy(seal_payload + 8, segment_hash, sizeof(segment_hash)); - - if (log_count == 0u) { - new_logseq = 1u; - } else { - if (log_records[log_count - 1u].logseq == UINT64_MAX) { - amduat_reference_free(&derived_ref); - amduat_octets_free(&artifact_bytes); - amduat_asl_store_index_fs_log_free(log_records, log_count); - free(log_path); - free(index_path); - free(segments_path); - free(blocks_path); - free(seal_payload); - return AMDUAT_ASL_STORE_ERR_IO; - } - new_logseq = log_records[log_count - 1u].logseq + 1u; - } - log_records[log_count].logseq = new_logseq; - log_records[log_count].record_type = AMDUAT_ASL_LOG_RECORD_SEGMENT_SEAL; - log_records[log_count].payload = amduat_octets(seal_payload, seal_len); - memset(log_records[log_count].record_hash, 0, - sizeof(log_records[log_count].record_hash)); - log_count += 1u; - - err = amduat_asl_store_index_fs_write_log(log_path, index_path, - log_records, log_count); - amduat_asl_store_index_fs_log_free(log_records, log_count); - free(log_path); + err = amduat_asl_store_index_fs_append_log_record_unlocked( + fs, + AMDUAT_ASL_LOG_RECORD_SEGMENT_SEAL, + seal_payload, + seal_len, + NULL); + free(seal_payload); free(index_path); free(segments_path); free(blocks_path); @@ -4596,7 +4712,7 @@ static amduat_asl_store_error_t amduat_asl_store_index_fs_put_indexed_unlocked_i *out_ref = derived_ref; amduat_asl_store_index_fs_fill_index_state(out_state, current_state.snapshot_id, - new_logseq); + fs->log_tail_logseq); amduat_asl_store_index_fs_update_ingest_state(fs, artifact_len); amduat_asl_store_index_fs_maybe_snapshot_size(fs); return AMDUAT_ASL_STORE_OK; @@ -4800,6 +4916,7 @@ amduat_asl_store_error_t amduat_asl_store_index_fs_snapshot_create( free(manifest_path); return err; } + fs->log_tail_initialized = false; { amduat_asl_snapshot_manifest_t verify_manifest; @@ -5224,6 +5341,11 @@ bool amduat_asl_store_index_fs_init(amduat_asl_store_index_fs_t *fs, fs->last_ingest_time_ns = 0u; fs->next_snapshot_id = 0u; fs->snapshot_state_initialized = false; + fs->log_tail_initialized = false; + fs->log_tail_logseq = 0u; + memset(fs->log_tail_hash, 0, sizeof(fs->log_tail_hash)); + fs->skip_exists_precheck = amduat_asl_store_index_fs_env_truthy( + getenv("AMDUAT_ASL_INDEX_FS_SKIP_EXISTS_PRECHECK")); fs->open_segments = NULL; fs->write_depth = 0u; fs->write_lock_fd = -1;