/// <summary> /// Drop collection including all documents, indexes and extended pages (do not support transactions) /// </summary> public bool DropCollection(string name) { if (name.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(name)); } // drop collection is possible only in exclusive transaction for this if (_locker.IsInTransaction) { throw LiteException.AlreadyExistsTransaction(); } return(this.AutoTransaction(transaction => { var snapshot = transaction.CreateSnapshot(LockMode.Write, name, false); // if collection do not exist, just exit if (snapshot.CollectionPage == null) { return false; } // call drop collection service snapshot.DropCollection(transaction.Safepoint); // remove sequence number (if exists) _sequences.TryRemove(name, out var dummy); return true; })); }
/// <summary> /// Drop collection including all documents, indexes and extended pages (do not support transactions) /// </summary> public async Task <bool> DropCollectionAsync(string name) { if (name.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(name)); } // drop collection is possible only in exclusive transaction for this if (_transaction != null) { throw LiteException.AlreadyExistsTransaction(); } return(await this.AutoTransaction(async transaction => { var snapshot = await transaction.CreateSnapshot(LockMode.Write, name, false); // if collection do not exist, just exit if (snapshot.CollectionPage == null) { return false; } LOG($"drop collection `{name}`", "COMMAND"); // call drop collection service //await snapshot.DropCollection(transaction.Safepoint); throw new NotImplementedException(); // remove sequence number (if exists) //_sequences.TryRemove(name, out var dummy); return true; })); }
/// <summary> /// Rename a collection (do not support transactions) /// </summary> public bool RenameCollection(string collection, string newName) { if (collection.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(collection)); } if (newName.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(newName)); } // rename collection is possible only in exclusive transaction for this if (_locker.IsInTransaction) { throw LiteException.AlreadyExistsTransaction(); } // check for collection name if (collection.Equals(newName, StringComparison.OrdinalIgnoreCase)) { throw LiteException.InvalidCollectionName(newName, "New name must be different from current name"); } // checks if newName are compatible CollectionService.CheckName(newName, _header); // rename collection is possible only in exclusive transaction for this if (_locker.IsInTransaction) { throw LiteException.AlreadyExistsTransaction(); } return(this.AutoTransaction(transaction => { var currentSnapshot = transaction.CreateSnapshot(LockMode.Write, collection, false); var newSnapshot = transaction.CreateSnapshot(LockMode.Write, newName, false); if (currentSnapshot.CollectionPage == null) { return false; } // checks if do not already exists this collection name if (_header.GetCollectionPageID(newName) != uint.MaxValue) { throw LiteException.AlreadyExistsCollectionName(newName); } // rename collection and set page as dirty (there is no need to set IsDirty in HeaderPage) transaction.Pages.Commit += (h) => { h.RenameCollection(collection, newName); }; return true; })); }
/// <summary> /// Rename a collection (do not support transactions) /// </summary> public bool RenameCollection(string collection, string newName) { if (collection.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(collection)); } if (newName.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(newName)); } if (collection.Equals(newName, StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException("To rename a collection the new name must be different from current collection name"); } // rename collection is possible only in exclusive transaction for this if (_locker.IsInTransaction) { throw LiteException.AlreadyExistsTransaction(); } return(this.AutoTransaction(transaction => { var currentSnapshot = transaction.CreateSnapshot(LockMode.Write, collection, false); var newSnapshot = transaction.CreateSnapshot(LockMode.Write, newName, false); if (currentSnapshot.CollectionPage == null) { return false; } var diff = Encoding.UTF8.GetByteCount(newName) - Encoding.UTF8.GetByteCount(collection); // check if new size fit on header page if (diff > 0 && diff > _header.GetAvaiableCollectionSpace()) { throw new LiteException(0, "This is no space to rename this collection"); } // checks if do not already exists this collection name if (_header.GetCollectionPageID(newName) != uint.MaxValue) { throw LiteException.AlreadyExistsCollectionName(newName); } // rename collection and set page as dirty (there is no need to set IsDirty in HeaderPage) transaction.Pages.Commit += (h) => { h.RenameCollection(collection, newName); }; return true; })); }
/// <summary> /// Enter transaction read lock /// </summary> public void EnterTransaction() { // if current thread are in reserved mode, do not enter in transaction if (_transaction.IsWriteLockHeld) { return; } try { if (_transaction.TryEnterReadLock(_timeout) == false) { throw LiteException.LockTimeout("transaction", _timeout); } } catch (LockRecursionException) { throw LiteException.AlreadyExistsTransaction(); } }
/// <summary> /// Set engine pragma new value (some pragmas will be affected only after realod) /// </summary> public bool Pragma(string name, BsonValue value) { if (this.Pragma(name) == value) { return(false); } if (_locker.IsInTransaction) { throw LiteException.AlreadyExistsTransaction(); } // do a inside transaction to edit pragma on commit event return(this.AutoTransaction(transaction => { transaction.Pages.Commit += (h) => { h.Pragmas.Set(name, value, true); }; return true; })); }
/// <summary> /// Set engine pragma new value (some pragmas will be affected only after realod) /// </summary> public async Task <bool> PragmaAsync(string name, BsonValue value) { if (this.Pragma(name) == value) { return(false); } if (_transaction != null) { throw LiteException.AlreadyExistsTransaction(); } // do a inside transaction to edit pragma on commit event return(await this.AutoTransaction(transaction => { transaction.Pages.Commit += (h) => { h.Pragmas.Set(name, value, true); }; return Task.FromResult(true); })); }
/// <summary> /// Analyze collection indexes to update UniqueKey counter. If collections parameter are null, analyze all collections /// </summary> public int Analyze(string[] collections) { // collection analyze is possible only in exclusive transaction for this if (_locker.IsInTransaction) { throw LiteException.AlreadyExistsTransaction(); } var cols = collections == null || collections.Length == 0 ? _header.GetCollections().Select(x => x.Key).ToArray() : collections; var count = 0; foreach (var collection in cols) { // counters for indexes var keyCount = new Dictionary <string, uint>(); var keyUniqueCount = new Dictionary <string, uint>(); // create one transaction per colection to avoid lock all database this.AutoTransaction(transaction => { // first, get read-only snapshot var snapshot = transaction.CreateSnapshot(LockMode.Read, collection, false); // do not use "col" local variable because `WriteMode()` clear _collectionPage instance if (snapshot.CollectionPage == null) { return(0); } LOG($"analyze `{collection}`", "COMMAND"); var indexer = new IndexService(snapshot); var indexes = snapshot.CollectionPage.GetCollectionIndexes().ToArray(); foreach (var index in indexes) { var last = BsonValue.MinValue; var counter = 0u; var uniqueCounter = 0u; foreach (var node in indexer.FindAll(index, LiteDB.Query.Ascending)) { counter++; uniqueCounter += node.Key == last ? 0u : 1u; last = node.Key; } keyCount[index.Name] = counter; keyUniqueCount[index.Name] = uniqueCounter; } // after do all analyze, update snapshot to write mode snapshot = transaction.CreateSnapshot(LockMode.Write, collection, false); foreach (var name in indexes.Select(x => x.Name)) { // will get index and set as dirty var index = snapshot.CollectionPage.UpdateCollectionIndex(name); index.KeyCount = keyCount[index.Name]; index.UniqueKeyCount = keyUniqueCount[index.Name]; } snapshot.CollectionPage.LastAnalyzed = DateTime.Now; snapshot.CollectionPage.IsDirty = true; return(++count); }); } return(count); }