/// <summary> /// Reclaim unused space (Directly on the table, stopping the defragmentation can result in permanent corruption) /// </summary> /// <returns>The number of bytes saved</returns> public async ValueTask <int> UnsafeDefragment(CancellationToken cancellationToken = default) { ClearTrie(); await ClearFileStream(); int saved = 0; var fileName = await tx.Schema.GetFileNameOrCreate(tableName); if (!await tx._Engine.Storages.Exists(fileName.ToString())) { return(0); } await using var fs = await tx._Engine.Storages.OpenStorage(fileName.ToString()); await using var cache = new CacheStorage(fs, false, PagePool, true); var trie = await LTrie.OpenFromStorage(cache); saved = await trie.Defragment(cancellationToken); await cache.Flush(); await fs.Flush(); return(saved); }
/// <summary> /// Reclaim unused space (Copy the table in a temporary file, defragment and replace the original table) /// </summary> /// <returns>The number of bytes saved</returns> public async ValueTask <int> Defragment(CancellationToken cancellationToken = default) { ClearTrie(); await ClearFileStream(); // We copy the current table on a temporary file, then defragment that // once defragmentation is complete, we copy the temp file to the current table // this prevent corruption if anything happen on the middle of the defragmentation var fileName = await tx.Schema.GetFileNameOrCreate(tableName); var tmpFile = $"{fileName}_tmp"; if (!await tx._Engine.Storages.Exists(fileName.ToString())) { return(0); } await tx._Engine.Storages.Copy(fileName.ToString(), tmpFile); int saved = 0; try { await using var fs = await tx._Engine.Storages.OpenStorage(tmpFile); await using var cache = new CacheStorage(fs, false, PagePool, true); var trie = await LTrie.OpenFromStorage(cache); saved = await trie.Defragment(cancellationToken); await cache.Flush(); await fs.Flush(); } catch { await tx._Engine.Storages.Delete(tmpFile); throw; } await tx._Engine.Storages.Move(tmpFile, fileName.ToString()); return(saved); }