예제 #1
0
        /// <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;
            }));
        }
예제 #2
0
        /// <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;
            }));
        }
예제 #3
0
        /// <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;
            }));
        }
예제 #4
0
        /// <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;
            }));
        }
예제 #5
0
        /// <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();
            }
        }
예제 #6
0
        /// <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;
            }));
        }
예제 #7
0
        /// <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);
            }));
        }
예제 #8
0
        /// <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);
        }