/// <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); } 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); }
/// <summary> /// Delete current collection and all pages - this snapshot can't be used after this /// </summary> public void DropCollection(Action safePoint) { var indexer = new IndexService(this, _header.Pragmas.Collation); // CollectionPage will be last deleted page (there is no NextPageID from CollectionPage) _transPages.FirstDeletedPageID = _collectionPage.PageID; _transPages.LastDeletedPageID = _collectionPage.PageID; // mark collection page as empty _collectionPage.MarkAsEmtpy(); _transPages.DeletedPages = 1; var indexPages = new HashSet <uint>(); // getting all indexes pages from all indexes foreach (var index in _collectionPage.GetCollectionIndexes()) { // add head/tail (same page) to be deleted indexPages.Add(index.Head.PageID); foreach (var node in indexer.FindAll(index, Query.Ascending)) { indexPages.Add(node.Page.PageID); safePoint(); } } // now, mark all pages as deleted foreach (var pageID in indexPages) { var page = this.GetPage <IndexPage>(pageID); // mark page as delete and fix deleted page list page.MarkAsEmtpy(); page.NextPageID = _transPages.FirstDeletedPageID; _transPages.FirstDeletedPageID = page.PageID; _transPages.DeletedPages++; safePoint(); } // adding all data pages foreach (var startPageID in _collectionPage.FreeDataPageList) { var next = startPageID; while (next != uint.MaxValue) { var page = this.GetPage <DataPage>(next); next = page.NextPageID; // mark page as delete and fix deleted page list page.MarkAsEmtpy(); page.NextPageID = _transPages.FirstDeletedPageID; _transPages.FirstDeletedPageID = page.PageID; _transPages.DeletedPages++; safePoint(); } } // remove collection name (in header) at commit time _transPages.Commit += (h) => h.DeleteCollection(_collectionName); }
private IEnumerable <IndexNode> ExecuteLike(IndexService indexer, CollectionIndex index) { return(indexer .FindAll(index, this.Order) .Where(x => x.Key.IsString && x.Key.AsString.SqlLike(_pattern, indexer.Collation))); }