Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions src/FileSearch.Core/Indexing/IndexDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace FileSearch.Core.Indexing;
/// </summary>
internal sealed class IndexDatabase : IDisposable
{
internal const string CurrentSchemaVersion = "25";
internal const string CurrentSchemaVersion = "26";
private static readonly TimeSpan CompactLeaseDrainTimeout = TimeSpan.FromSeconds(5);

/// <summary>
Expand Down Expand Up @@ -715,17 +715,17 @@ private static async Task EnsureMetaTableAsync(Database db, CancellationToken ca

private async Task EnsureSchemaAsync(Database db, CancellationToken cancellationToken)
{
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS index_volumes (id INTEGER PRIMARY KEY, volume_key TEXT, volume_serial TEXT, filesystem_name TEXT, is_remote INTEGER, usn_supported INTEGER, drive_kind TEXT, journal_id TEXT, last_committed_usn INTEGER, health TEXT, last_checked_utc_ticks INTEGER, last_error TEXT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS index_roots (id INTEGER PRIMARY KEY, root_path TEXT, indexed_utc_ticks INTEGER, options_hash TEXT, volume_id INTEGER, last_full_scan_utc_ticks INTEGER, root_file_reference_number TEXT, root_parent_file_reference_number TEXT, content_version TEXT, location_kind TEXT, update_strategy TEXT, strategy_warning TEXT, usn_catch_up_enabled INTEGER, watcher_recommended INTEGER, last_full_validation_utc_ticks INTEGER, last_validation_status TEXT, last_validation_message TEXT, last_validation_files_checked INTEGER, last_validation_missing_from_index_count INTEGER, last_validation_changed_count INTEGER, last_validation_missing_from_disk_count INTEGER, last_validation_failed_count INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS index_directories (id INTEGER PRIMARY KEY, root_id INTEGER, path TEXT, volume_id INTEGER, directory_reference_number TEXT, parent_file_reference_number TEXT, observed_utc_ticks INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS files (id INTEGER PRIMARY KEY, root_id INTEGER, path TEXT, path_lower TEXT, directory_path TEXT, directory_path_lower TEXT, file_name TEXT, file_name_lower TEXT, extension TEXT, size_bytes INTEGER, created_utc_ticks INTEGER, modified_utc_ticks INTEGER, attributes INTEGER, file_type_category TEXT, indexed_utc_ticks INTEGER, status TEXT, error TEXT, volume_id INTEGER, file_reference_number TEXT, parent_file_reference_number TEXT, last_observed_usn INTEGER, content_version TEXT, open_count INTEGER, last_opened_utc_ticks INTEGER, extractor_id TEXT, extractor_version TEXT, extraction_attempt_count INTEGER, last_extraction_attempt_utc_ticks INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS extraction_issues (id INTEGER PRIMARY KEY, file_id INTEGER, member_path TEXT, code TEXT, message TEXT, severity TEXT, created_utc_ticks INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS validation_drifts (id INTEGER PRIMARY KEY, root_id INTEGER, path TEXT, kind TEXT, message TEXT, observed_utc_ticks INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS file_metadata_tokens (id INTEGER PRIMARY KEY, root_id INTEGER, file_id INTEGER, token TEXT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS index_volumes (id INTEGER PRIMARY KEY, volume_key TEXT, volume_serial TEXT, filesystem_name TEXT, is_remote INTEGER, usn_supported INTEGER, drive_kind TEXT, journal_id TEXT, last_committed_usn INTEGER, health TEXT, last_checked_utc_ticks BIGINT, last_error TEXT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS index_roots (id INTEGER PRIMARY KEY, root_path TEXT, indexed_utc_ticks BIGINT, options_hash TEXT, volume_id INTEGER, last_full_scan_utc_ticks BIGINT, root_file_reference_number TEXT, root_parent_file_reference_number TEXT, content_version TEXT, location_kind TEXT, update_strategy TEXT, strategy_warning TEXT, usn_catch_up_enabled INTEGER, watcher_recommended INTEGER, last_full_validation_utc_ticks BIGINT, last_validation_status TEXT, last_validation_message TEXT, last_validation_files_checked INTEGER, last_validation_missing_from_index_count INTEGER, last_validation_changed_count INTEGER, last_validation_missing_from_disk_count INTEGER, last_validation_failed_count INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS index_directories (id INTEGER PRIMARY KEY, root_id INTEGER, path TEXT, volume_id INTEGER, directory_reference_number TEXT, parent_file_reference_number TEXT, observed_utc_ticks BIGINT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS files (id INTEGER PRIMARY KEY, root_id INTEGER, path TEXT, path_lower TEXT, directory_path TEXT, directory_path_lower TEXT, file_name TEXT, file_name_lower TEXT, extension TEXT, size_bytes INTEGER, created_utc_ticks BIGINT, modified_utc_ticks BIGINT, attributes INTEGER, file_type_category TEXT, indexed_utc_ticks BIGINT, status TEXT, error TEXT, volume_id INTEGER, file_reference_number TEXT, parent_file_reference_number TEXT, last_observed_usn INTEGER, content_version TEXT, open_count INTEGER, last_opened_utc_ticks BIGINT, extractor_id TEXT, extractor_version TEXT, extraction_attempt_count INTEGER, last_extraction_attempt_utc_ticks BIGINT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS extraction_issues (id INTEGER PRIMARY KEY, file_id INTEGER, member_path TEXT, code TEXT, message TEXT, severity TEXT, created_utc_ticks BIGINT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS validation_drifts (id INTEGER PRIMARY KEY, root_id INTEGER, path TEXT, kind TEXT, message TEXT, observed_utc_ticks BIGINT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS file_metadata_tokens (id BIGINT PRIMARY KEY, root_id INTEGER, file_id INTEGER, token TEXT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS content_units (id INTEGER PRIMARY KEY, file_id INTEGER, kind TEXT, locator_json TEXT, unit_text TEXT, content_hash TEXT, language TEXT, extractor_id TEXT, extractor_version TEXT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS lines (id INTEGER PRIMARY KEY, file_id INTEGER, content_unit_id INTEGER, line_number INTEGER, content TEXT, anchor_json TEXT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS file_trigrams (root_id INTEGER, trigram_code INTEGER, file_id INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS pending_changes (id INTEGER PRIMARY KEY, root_path TEXT, path TEXT, kind INTEGER, queued_utc_ticks INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS file_trigrams (root_id INTEGER, trigram_code BIGINT, file_id INTEGER)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS pending_changes (id INTEGER PRIMARY KEY, root_path TEXT, path TEXT, kind INTEGER, queued_utc_ticks BIGINT)", cancellationToken).ConfigureAwait(false);
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS index_sequences (name TEXT PRIMARY KEY, next_id INTEGER)", cancellationToken).ConfigureAwait(false);

await TryExecuteAsync(db, "CREATE UNIQUE INDEX IF NOT EXISTS idx_index_roots_path ON index_roots(root_path)", cancellationToken).ConfigureAwait(false);
Expand Down
25 changes: 25 additions & 0 deletions tests/FileSearch.Core.Tests/FileIndexTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,31 @@ public async Task CurrentSchemaWithMissingColumnsIsTreatedAsMissingUntilRebuilt(
Assert.EndsWith("shape-rebuilt.txt", hit.Path);
}

[Fact]
public async Task CurrentSchemaStoresUtcTicksAsBigInt()
{
File.WriteAllText(Path.Combine(_root, "bigint-schema.txt"), "bigint schema needle\n");
await BuildAsync();

const long largeTickValue = 639219823516075047;
await using var db = await Database.OpenAsync(_dbPath, TestContext.Current.CancellationToken);
await db.ExecuteAsync($"UPDATE index_roots SET indexed_utc_ticks = {largeTickValue}", TestContext.Current.CancellationToken);
await db.ExecuteAsync($"UPDATE index_volumes SET last_checked_utc_ticks = {largeTickValue}", TestContext.Current.CancellationToken);
await db.ExecuteAsync($"UPDATE files SET created_utc_ticks = {largeTickValue}", TestContext.Current.CancellationToken);

await AssertAnyRowMatchesAsync("index_roots", "indexed_utc_ticks");
await AssertAnyRowMatchesAsync("files", "created_utc_ticks");

async Task AssertAnyRowMatchesAsync(string table, string column)
{
await using var result = await db.ExecuteAsync(
$"SELECT COUNT(*) FROM {table} WHERE {column} = {largeTickValue}",
TestContext.Current.CancellationToken);
Assert.True(await result.MoveNextAsync(TestContext.Current.CancellationToken));
Assert.True(result.Current[0].AsInteger > 0);
}
}

[Fact]
public async Task IndexedSearchToleratesWalCleanupContention()
{
Expand Down