/// <summary> /// Reduce disk size re-arranging unused spaces. Can change password. If temporary disk was not provided, use MemoryStream temp disk /// </summary> public long Shrink(string password = null, IDiskService tempDisk = null) { var originalSize = _disk.FileLength; // if temp disk are not passed, use memory stream disk using (var temp = tempDisk ?? new StreamDiskService(new MemoryStream())) using (_locker.Write()) using (var engine = new LiteEngine(temp, password)) { // read all collection foreach (var collectionName in this.GetCollectionNames()) { // first create all user indexes (exclude _id index) foreach (var index in this.GetIndexes(collectionName).Where(x => x.Field != "_id")) { engine.EnsureIndex(collectionName, index.Field, index.Unique); } // now copy documents var docs = this.Find(collectionName, Query.All()); engine.InsertBulk(collectionName, docs); // fix collection sequence number var seq = _collections.Get(collectionName).Sequence; engine.Transaction(collectionName, true, (col) => { col.Sequence = seq; engine._pager.SetDirty(col); return(true); }); } // copy user version engine.UserVersion = this.UserVersion; // set current disk size to exact new disk usage _disk.SetLength(temp.FileLength); // read new header page to start copy var header = BasePage.ReadPage(temp.ReadPage(0)) as HeaderPage; // copy (as is) all pages from temp disk to original disk for (uint i = 0; i <= header.LastPageID; i++) { // skip lock page if (i == 1) { continue; } var page = temp.ReadPage(i); _disk.WritePage(i, page); } // create/destroy crypto class if (_crypto != null) { _crypto.Dispose(); } _crypto = password == null ? null : new AesEncryption(password, header.Salt); // initialize all services again (crypto can be changed) this.InitializeServices(); // return how many bytes are reduced return(originalSize - temp.FileLength); } }