public TextDeferredIndexer(DBreezeEngine engine) { this.DBreezeEngine = engine; LTrieSettings = new TrieSettings() { InternalTable = true }; Storage = new StorageLayer(Path.Combine(engine.MainFolder, TableFileName), LTrieSettings, engine.Configuration); LTrie = new LTrie(Storage); LTrie.TableName = "DBreeze.TextIndexer"; if (LTrie.Storage.Length > 100000) //Recreating file if its size more then 100KB and it is empty { if (LTrie.Count(true) == 0) { LTrie.Storage.RecreateFiles(); LTrie.Dispose(); Storage = new StorageLayer(Path.Combine(engine.MainFolder, TableFileName), LTrieSettings, engine.Configuration); LTrie = new LTrie(Storage); LTrie.TableName = "DBreeze.TextIndexer"; } } if (LTrie.Count(true) > 0) { this.StartDefferedIndexing(); } }
public NestedTableInternal(bool tableExists, LTrie masterTrie, long rootStart, long shiftFromValueStart, bool useCache, LTrie parentTrie, ref byte[] key) { //DbInTableStorage - Dispose and Recreate (Stay Empty) ///////////////////////////////// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GET RID OF , bool useCache ///////////////////////////////// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GET RID OF MASTER TABLE INSERT (table can be created by read thread also) TableExists = tableExists; if (tableExists) { _useCache = useCache; _shiftFromValueStart = shiftFromValueStart; //Flag distinguish between masterTrie.InsertTable or masterTrie.SelectTable (InsertTable, creates tables if they don't exist) //_masterTableInsert = masterTableInsert; _masterTrie = masterTrie; _parentTable = parentTrie; _key = key; _rootStart = rootStart; TrieSettings trieSettings = new TrieSettings() { ROOT_START = rootStart, IsNestedTable = true }; _storage = new NestedTableStorage(masterTrie.Cache.Trie.Storage, trieSettings); //Then trie receives ITableFile wrapper with new settings table = new LTrie(_storage); } }
/// <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> /// Can return NULL (if DbIsNotOperatable) /// </summary> /// <param name="tableName"></param> /// <param name="transactionThreadId"></param> /// <returns></returns> public LTrie GetTable_WRITE(string tableName, int transactionThreadId) { if (!this._engine.DBisOperable) { return(null); } TransactionUnit transactionUnit = this.GetTransactionUnit(transactionThreadId); if (transactionUnit != null) { #if NET35 || NETr40 if (System.Threading.Thread.CurrentThread.ManagedThreadId != transactionThreadId) #else if (Environment.CurrentManagedThreadId != transactionThreadId) #endif { this.UnregisterTransaction(transactionThreadId); throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.TRANSACTION_CANBEUSED_FROM_ONE_THREAD); } //We must put Get_Table_Write through the same bottleneck as RegisterWriteTablesForTransaction this.RegisterWriteTablesForTransaction(transactionThreadId, new List <string> { tableName }, false); //it will wait here till table for writing, reserved by other thread is released LTrie tbl = null; try { tbl = this._engine.DBreezeSchema.GetTable(tableName); //Adding table to transaction unit with the ITransactable interface transactionUnit.AddTransactionWriteTable(tableName, tbl); //added together with ITransactable //TODO - THIS TABLE LTrie must be Interfaced //Telling to the table that transactionThreadId Thread will modify it tbl.ModificationThreadId(transactionThreadId); } catch (Exception ex) { //Exception must come from Schema, by in-ability to get the table this.UnregisterTransaction(transactionThreadId); //CIRCULAR PARTLY throw ex; } return(tbl); } else { throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.TRANSACTION_DOESNT_EXIST); } }
/// <summary> /// Flushing all /// </summary> public void Flush() { if (!isUsed) { return; } LTrie table = null; bool WasOperated = false; byte[] deletedValue = null; byte[] btKey = null; byte[] btVal = null; foreach (var el1 in _dRemove.OrderBy(r => r.Key)) { if (!tbls.TryGetValue(el1.Key, out table)) { table = _t.GetWriteTableFromBuffer(el1.Key); tbls[el1.Key] = table; } foreach (var el2 in el1.Value.OrderBy(r => r.Key)) { //_t.RemoveKey<byte[]>(el1.Key, el2.Value); btKey = el2.Value; table.Remove(ref btKey, out WasOperated, false, out deletedValue); } } _dRemove.Clear(); foreach (var el1 in _dInsert.OrderBy(r => r.Key)) { if (!tbls.TryGetValue(el1.Key, out table)) { table = _t.GetWriteTableFromBuffer(el1.Key); tbls[el1.Key] = table; } //List<string> tt = el1.Value.OrderBy(r => r.Key).Select(r => r.Key).ToList(); foreach (var el2 in el1.Value.OrderBy(r => r.Key)) { //_t.Insert<byte[], byte[]>(el1.Key, el2.Value.Key, el2.Value.Value); btKey = el2.Value.Key; btVal = el2.Value.Value; table.Add(ref btKey, ref btVal, out WasOperated, false); } } _dInsert.Clear(); _cnt.Clear(); WasAutomaticallyFlushed = false; isUsed = false; }
public void Setup() { t = new Tester(); t.ConsistencyCheck = false; key = Encoding.UTF8.GetBytes("cf6c9e8cb9fb312862edbd5c2b7d1615db4f65ab"); fs = t.CreateFileStorage("10000007", true, "Benchmark"); trie = t.CreateTrie(fs, false).GetAwaiter().GetResult(); (trie.EnumerateStartsWith("").ToArrayAsync().GetAwaiter().GetResult()).DisposeAll(); }
/// <summary> /// constructor /// </summary> /// <param name="engine"></param> internal DBreezeResources(DBreezeEngine engine) { this.DBreezeEngine = engine; LTrieSettings = new TrieSettings() { InternalTable = true }; Storage = new StorageLayer(Path.Combine(engine.MainFolder, TableFileName), LTrieSettings, engine.Configuration); LTrie = new LTrie(Storage); LTrie.TableName = "DBreezeResources"; }
internal async ValueTask <LTrie> GetTrie() { if (trie is LTrie) { return(trie); } AssertNotClosed(); trie = await LTrie.OpenOrInitFromStorage(await GetCacheStorage()); trie.ConsistencyCheck = checkConsistency; return(trie); }
public void Flush(string tableName) { LTrie table = null; bool WasOperated = false; byte[] deletedValue = null; byte[] btKey = null; byte[] btVal = null; if (_dRemove.ContainsKey(tableName)) { if (!tbls.TryGetValue(tableName, out table)) { table = _t.GetWriteTableFromBuffer(tableName); tbls[tableName] = table; } foreach (var el2 in _dRemove[tableName].OrderBy(r => r.Key)) { // _t.RemoveKey<byte[]>(tableName, el2.Value); btKey = el2.Value; table.Remove(ref btKey, out WasOperated, false, out deletedValue); } _dRemove[tableName].Clear(); _dRemove.Remove(tableName); } if (_dInsert.ContainsKey(tableName)) { if (!tbls.TryGetValue(tableName, out table)) { table = _t.GetWriteTableFromBuffer(tableName); tbls[tableName] = table; } foreach (var el2 in _dInsert[tableName].OrderBy(r => r.Key)) { //_t.Insert<byte[],byte[]>(tableName, el2.Value.Key, el2.Value.Value); btKey = el2.Value.Key; btVal = el2.Value.Value; table.Add(ref btKey, ref btVal, out WasOperated, false); } _dInsert[tableName].Clear(); _dInsert.Remove(tableName); } _cnt[tableName] = 0; WasAutomaticallyFlushed = true; }
private static async ValueTask <DBTrieEngine> OpenFromStorages(IStorages storages) { if (storages == null) { throw new ArgumentNullException(nameof(storages)); } var schemaFile = await storages.OpenStorage(Schema.StorageName); var trie = await LTrie.OpenOrInitFromStorage(schemaFile); var s = await Schema.OpenOrInitFromTrie(trie); return(new DBTrieEngine(storages, s)); }
public LTrieRootNode(LTrie tree) { Tree = tree; DefaultPointerLen = Tree.Storage.TrieSettings.POINTER_LENGHT; DefaultRootSize = Tree.Storage.TrieSettings.ROOT_SIZE; //me = new byte[Tree.Storage.TreeSettings.ROOT_SIZE]; LinkToZeroNode = new byte[DefaultPointerLen]; this.EmptyPointer = new byte[DefaultPointerLen]; //Reading Root Node this.ReadRootNode(); }
/// <summary> /// Can return NULL if table doesn't exist /// Can return NULL (if DbIsNotOperatable) /// /// Differs from GetTable_Write: /// 1. table is not registered for Write; /// 2. Table is not created, if doesn't exist. /// </summary> /// <param name="tableName"></param> /// <param name="transactionThreadId"></param> /// <param name="ignoreThreadIdCheck"></param> /// <returns></returns> public LTrie GetTable_READ(string tableName, int transactionThreadId, bool ignoreThreadIdCheck = false) { if (!this._engine.DBisOperable) { return(null); } TransactionUnit transactionUnit = this.GetTransactionUnit(transactionThreadId); if (transactionUnit != null) { #if NET35 || NETr40 if (!ignoreThreadIdCheck && System.Threading.Thread.CurrentThread.ManagedThreadId != transactionThreadId) #else if (!ignoreThreadIdCheck && Environment.CurrentManagedThreadId != transactionThreadId) #endif { this.UnregisterTransaction(transactionThreadId); throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.TRANSACTION_CANBEUSED_FROM_ONE_THREAD); } LTrie tbl = null; try { if (!this._engine.DBreezeSchema.IfUserTableExists(tableName)) { return(null); } tbl = this._engine.DBreezeSchema.GetTable(tableName); } catch (Exception ex) { //Exception must come from Schema, by in-ability to get the table this.UnregisterTransaction(transactionThreadId); //CIRCULAR PARTLY throw ex; } return(tbl); } else { throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.TRANSACTION_DOESNT_EXIST); } }
/* TODO * * 1. HERE we will add TableNames as RegEx with settings * 2. Checking Reserverd TableNames prefixes * 3. User TableName must start from @ut * 4. GetPhysicalPathToTheUserTable - File with DIrectory Settings for different tables parser (to make reside different tables in different HDDs or even network drives) */ private void OpenSchema() { LTrieSettings = new TrieSettings() { InternalTable = true, //SkipStorageBuffer = true }; Storage = new StorageLayer(Path.Combine(Engine.MainFolder, SchemaFileName), LTrieSettings, Engine.Configuration); LTrie = new LTrie(Storage); LTrie.TableName = "DBreeze.Scheme"; //Reading lastFileNumber ReadUserLastFileNumber(); }
internal static async ValueTask <Schema> OpenOrInitFromTrie(LTrie trie) { using var key = await trie.GetValue(LastFileNumberKey); ulong number = 10000000UL; if (key is LTrieValue) { number = await key.ReadValueULong(); } else { await trie.SetValue(LastFileNumberKey, number); await trie.Storage.Flush(); } return(new Schema(trie, number)); }
/// <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); }
//byte[] btKey = null; public Row(LTrieRow row, LTrie masterTrie, bool useCache) { if (row == null) { _exists = false; } else { _row = row; //_root = row._root; //_ptrToValue = row.LinkToValue; _exists = row.Exists; } _useCache = useCache; _masterTrie = masterTrie; if (_exists) { _key = DataTypesConvertor.ConvertBack <TKey>(row.Key); } }
private void Init() { try { LTrieSettings = new TrieSettings() { InternalTable = true, //SkipStorageBuffer = true }; Storage = new StorageLayer(Path.Combine(Engine.MainFolder, JournalFileName), LTrieSettings, Engine.Configuration); //Storage = new TrieDiskStorage(Path.Combine(Engine.MainFolder, JournalFileName), LTrieSettings, Engine.Configuration); LTrie = new LTrie(Storage); LTrie.TableName = "DBreeze.TranJournal"; this.RestoreNotFinishedTransactions(); } catch (Exception ex) { //CASCADE throw ex; } }
public void FinishTransaction(ulong tranNumber) { //_sync_transactionsTables.EnterReadLock(); _sync_transactionsTables.EnterWriteLock(); try { Dictionary <string, ITransactable> tbls = null; _transactionsTables.TryGetValue(tranNumber, out tbls); if (tbls != null) { //Starting procedure //1. Saving all table names into db - needed in case if something happens (Power loss or whatever). // Then restarted TransactionalJournal will delete rollback files for these tables (they are all committed) List <string> committedTablesNames = new List <string>(); foreach (var tt in tbls) { committedTablesNames.Add(tt.Key); } string serTbls = committedTablesNames.SerializeXml(); byte[] btSerTbls = System.Text.Encoding.UTF8.GetBytes(serTbls); byte[] key = tranNumber.To_8_bytes_array_BigEndian(); LTrie.Add(ref key, ref btSerTbls); LTrie.Commit(); //2. Calling transaction End for all tables try { foreach (var tt in tbls) { tt.Value.ITRCommitFinished(); } } catch (Exception ex) { //CASCADE from ITRCommitFinished, brings to NON-OPERATABLE throw ex; } //3. Deleting Record in Journal LTrie.Remove(ref key); LTrie.Commit(); //Clearing transaction number tbls.Clear(); _transactionsTables.Remove(tranNumber); //When Transaction File becomes big we try to clean it. if (LTrie.Storage.Length > MaxlengthOfTransactionFile && _transactionsTables.Count() == 0) { LTrie.Storage.RecreateFiles(); LTrie.Dispose(); Storage = new StorageLayer(Path.Combine(Engine.MainFolder, JournalFileName), LTrieSettings, Engine.Configuration); LTrie = new LTrie(Storage); LTrie.TableName = "DBreeze.TranJournal"; } } } catch (System.Exception ex) { //CASCADE throw ex; } finally { _sync_transactionsTables.ExitWriteLock(); //_sync_transactionsTables.ExitReadLock(); } }
private void RestoreNotFinishedTransactions() { //TODO Trie settings from the table must be taken from schema (when they will differ) //STORE FILE NAME of rollback not table name try { byte[] btCommittedTablesNames = null; List <string> committedTablesNames = new List <string>(); if (LTrie.Count(false) == 0) //All ok { LTrie.RemoveAll(true); return; } string physicalPathToTheUserTable = String.Empty; //Settigns and storage for Committed tables !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MUST BE TAKEN FROM SCHEMA, FOR NOW DEFAULT TrieSettings ltrSet = null; IStorage storage = null; DBriize.LianaTrie.LTrie ltrie = null; foreach (var row in LTrie.IterateForward(true, false)) { btCommittedTablesNames = row.GetFullValue(true); committedTablesNames = System.Text.Encoding.UTF8.GetString(btCommittedTablesNames).DeserializeXml <List <string> >(); foreach (var fn in committedTablesNames) { //Trying to get path from the Schema, there is universal function for getting table physical TABLE FULL PATH /NAME physicalPathToTheUserTable = Engine.DBriizeSchema.GetPhysicalPathToTheUserTable(fn); //Returned path can be empty, if no more such table if (physicalPathToTheUserTable == String.Empty) { continue; } //We don't restore in-memory tables if (physicalPathToTheUserTable == "MEMORY") { continue; } //we open ltrie, and it automatically restores rollback ltrSet = new TrieSettings(); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MUST BE TAKEN FROM SCHEMA, FOR NOW DEFAULT //storage = new TrieDiskStorage(physicalPathToTheUserTable, ltrSet, Engine.Configuration); storage = new StorageLayer(physicalPathToTheUserTable, ltrSet, Engine.Configuration); ltrie = new LTrie(storage); //closing trie, that Schema could open it again ltrie.Dispose(); ////Deleting rollback file for such table //physicalPathToTheUserTable += ".rol"; //System.IO.File.Delete(physicalPathToTheUserTable); } committedTablesNames.Clear(); } //If all ok, recreate file LTrie.RemoveAll(true); } catch (OperationCanceledException ex) { throw ex; } //catch (System.Threading.ThreadAbortException ex) //{ // //We don'T make DBisOperable = false; // throw ex; //} catch (Exception) { //BRINGS TO DB NOT OPERATABLE this.Engine.DBisOperable = false; this.Engine.DBisOperableReason = "TransactionsCoordinator.RestoreNotFinishedTransaction"; //NOT CASCADE ADD EXCEPTION throw DBriizeException.Throw(DBriizeException.eDBriizeExceptions.CLEAN_ROLLBACK_FILES_FOR_FINISHED_TRANSACTIONS_FAILED); } }
//public OpenTable() //{ // Add(); //} public OpenTable(LTrie trie) { this.Trie = trie; Add(); }
internal Schema(LTrie trie, ulong lastFileNumber) { this.Trie = trie; this.LastFileNumber = lastFileNumber; }
public static async Task AssertExists(this LTrie trie, string key) { using var result = await trie.GetValue("@utTestTa"); Assert.NotNull(result); }
/// <summary> /// Returns table for READ, WRITE FUNC /// </summary> /// <param name="userTableName"></param> /// <returns></returns> internal LTrie GetTable(string userTableName) { string tableName = GetUserTableNameAsString(userTableName); //TODO pattern based mapping If table doesn't exist we create it with properties which could be supplied after db init as regex theme. //Schema protocol: 2 bytes - protocol version, other data //For protocol 1: first 8 bytes will be TheFileName, starting from db10000-dbN (0-N ulong). up to 10000 are reserved for dbreeze. //Table names are UTF-8 based, no limits ulong fileName = 0; OpenTable otl = null; _sync_openTablesHolder.EnterUpgradeableReadLock(); try { _openTablesHolder.TryGetValue(tableName, out otl); if (otl != null) { //Try to increase usage and return LTrie otl.Add(); return(otl.Trie); } //Probably table Exists in db but not in openTablesHolder _sync_openTablesHolder.EnterWriteLock(); try { //UpgradeableRead recheck _openTablesHolder.TryGetValue(tableName, out otl); if (otl != null) { //Try to increase usage and return LTrie otl.Add(); return(otl.Trie); } byte[] btTableName = GetUserTableNameAsByte(userTableName); //Trying to get fileName from cache fileName = this.cachedTableNames.GetFileName(tableName); // LTrieRow row = null; bool tableExists = false; if (fileName == 0) { LTrieRow row = LTrie.GetKey(btTableName, false, false); if (row.Exists) { tableExists = true; byte[] fullValue = row.GetFullValue(false); //Can be parsed different. First protocol version is 1 ushort schemeProtocol = fullValue.Substring(0, 2).To_UInt16_BigEndian(); switch (schemeProtocol) { case 1: fileName = fullValue.Substring(2, 8).To_UInt64_BigEndian(); break; default: throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.SCHEME_FILE_PROTOCOL_IS_UNKNOWN); } } else { tableExists = false; //Creating new table. //Checking table name validity //this will throw exception, if not valid DbUserTables.UserTableNameIsOk(userTableName); //Creating such table and renewing LastFileNumber counter //Adding to LastFileNumber LastFileNumber++; ////Deleting physical files related to the table, if they existed - normally they should not //DeleteAllReleatedTableFiles(Path.Combine(Engine.MainFolder, LastFileNumber.ToString())); byte[] lft = LastFileNumber.To_8_bytes_array_BigEndian(); //Writing this number to Schema file LTrie.Add(Encoding.UTF8.GetBytes(LastFileNumberKeyName), lft); //Creating table self and writing to Schema file LTrie.Add(btTableName, new byte[] { 0, 1 } //Protocol version 1 .Concat(lft)); //Number of the file //Committing both records LTrie.Commit(); fileName = LastFileNumber; this.cachedTableNames.Add(tableName, fileName); } } else { tableExists = true; } //Creating LTrie, adding it to _openTablesHolder //Seeting up Trie TableName, OTHER SETTINGS TrieSettings ts = new TrieSettings(); IStorage storage = null; ////Checking if default Flusg Disk behaviour was overriden //ts.DiskFlushBehaviour = Engine.Configuration.DiskFlushBehaviour; ////Checking if we have alternative DiskFlush behaviour //foreach (var pattern in Engine.Configuration.AlternativeDiskFlushBehaviour) //{ // //pattern.Key // if (DbUserTables.PatternsIntersect(pattern.Key, userTableName)) // { // ts.DiskFlushBehaviour = pattern.Value; // break; // } //} string alternativeTableLocation = String.Empty; if (CheckAlternativeTableLocationsIntersections(userTableName, out alternativeTableLocation)) { ts.StorageWasOverriden = true; if (alternativeTableLocation == String.Empty) { ts.AlternativeTableStorageType = DBreezeConfiguration.eStorage.MEMORY; storage = new StorageLayer(Path.Combine(Engine.MainFolder, fileName.ToString()), ts, Engine.Configuration); } else { ts.AlternativeTableStorageType = DBreezeConfiguration.eStorage.DISK; ts.AlternativeTableStorageFolder = alternativeTableLocation; DirectoryInfo diAlt = new DirectoryInfo(alternativeTableLocation); if (!diAlt.Exists) { diAlt.Create(); } if (!tableExists) { //Deleting physical files related to the table, if they existed - normally they should not DeleteAllReleatedTableFiles(Path.Combine(ts.AlternativeTableStorageFolder, LastFileNumber.ToString())); } storage = new StorageLayer(Path.Combine(ts.AlternativeTableStorageFolder, fileName.ToString()), ts, Engine.Configuration); } } else { if (!tableExists) { //Deleting physical files related to the table, if they existed - normally they should not DeleteAllReleatedTableFiles(Path.Combine(Engine.MainFolder, LastFileNumber.ToString())); } storage = new StorageLayer(Path.Combine(Engine.MainFolder, fileName.ToString()), ts, Engine.Configuration); } //storage = new StorageLayer(Path.Combine(Engine.MainFolder, fileName.ToString()), ts, Engine.Configuration); LTrie trie = new LTrie(storage); //Setting LTrie user table name trie.TableName = userTableName; //_openTablesHolder.Add(tableName, trie); //Automatically increased usage in OpenTable constructor _openTablesHolder.Add(tableName, new OpenTable(trie)); return(trie); } catch (System.Exception ex) { //CASCADE throw ex; } finally { _sync_openTablesHolder.ExitWriteLock(); } } catch (Exception ex) { throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.SCHEME_GET_TABLE_WRITE_FAILED, tableName, ex); } finally { _sync_openTablesHolder.ExitUpgradeableReadLock(); } }
public async ValueTask <LTrie> ReloadTrie(LTrie trie) { var trie2 = await CreateTrie(trie.Storage, trie.NodeCache is { });