Example #1
0
        /// <summary>
        /// Directly enumerates the contents of BPlusTree from disk in read-only mode.
        /// </summary>
        /// <param name="options"> The options normally used to create the <see cref="BPlusTree{TKey, TValue}"/> instance </param>
        /// <returns> Yields the Key/Value pairs found in the file </returns>
        public static IEnumerable <KeyValuePair <TKey, TValue> > EnumerateFile(BPlusTreeOptions <TKey, TValue> options)
        {
            options            = options.Clone();
            options.CreateFile = CreatePolicy.Never;
            options.ReadOnly   = true;

            using (INodeStorage store = options.CreateStorage())
            {
                bool           isnew;
                Node           root;
                IStorageHandle hroot = store.OpenRoot(out isnew);
                if (isnew)
                {
                    yield break;
                }

                NodeSerializer nodeReader = new NodeSerializer(options, new NodeHandleSerializer(store));
                if (isnew || !store.TryGetNode(hroot, out root, nodeReader))
                {
                    throw new InvalidDataException();
                }

                Stack <KeyValuePair <Node, int> > todo = new Stack <KeyValuePair <Node, int> >();
                todo.Push(new KeyValuePair <Node, int>(root, 0));

                while (todo.Count > 0)
                {
                    KeyValuePair <Node, int> cur = todo.Pop();
                    if (cur.Value == cur.Key.Count)
                    {
                        continue;
                    }

                    todo.Push(new KeyValuePair <Node, int>(cur.Key, cur.Value + 1));

                    Node child;
                    if (!store.TryGetNode(cur.Key[cur.Value].ChildNode.StoreHandle, out child, nodeReader))
                    {
                        throw new InvalidDataException();
                    }

                    if (child.IsLeaf)
                    {
                        for (int ix = 0; ix < child.Count; ix++)
                        {
                            var set        = child[ix].ToKeyValuePair();
                            var enumerator = set.Value.GetEnumerator();
                            while (enumerator.MoveNext())
                            {
                                yield return(new KeyValuePair <TKey, TValue>(set.Key, enumerator.Current.Key));
                            }
                        }
                    }
                    else
                    {
                        todo.Push(new KeyValuePair <Node, int>(child, 0));
                    }
                }
            }
        }
 static BPlusTreeOptions <TKey, TValue> Fix(BPlusTreeOptions <TKey, TValue> options)
 {
     if (options.LockingFactory.Create() is WriterOnlyLocking)
     {
         options.LockingFactory = new LockFactory <SimpleReadWriteLocking>();
     }
     return(options);
 }
 public NodeSerializer(BPlusTreeOptions <TKey, TValue> options, NodeHandleSerializer handleSerializer)
 {
     _options                 = options;
     _keySerializer           = options.KeySerializer;
     _valueSerializer         = options.ValueSerializer;
     _handleSerializer        = handleSerializer;
     _storageHandleSerializer = handleSerializer;
 }
Example #4
0
            public NodeCacheBase(BPlusTreeOptions <TKey, TValue> options)
            {
                Options     = options;
                LockFactory = Options.LockingFactory;
                Storage     = Options.CreateStorage();
                if (Options.UseStorageCache)
                {
                    Storage = new StorageCache(Storage, Options.CacheKeepAliveMaximumHistory);
                }

                NodeSerializer = new NodeSerializer(Options, new NodeHandleSerializer(Storage));
                _version       = new NodeVersion();
            }
Example #5
0
        /// <summary>
        /// Recovers as much file content as possible into a newly created <see cref="BPlusTree{TKey, TValue}"/>, if the operation returns
        /// a non-zero result it was successful and the file has been replaced with a new database containing
        /// the recovered data.  The original file remains in-tact but was renamed with a '.deleted' extension.
        /// </summary>
        /// <remarks>
        /// If an exception occurs during the parsing of the file and one or more records were recovered, they will
        /// be stored in a file by the same name with an added extension of '.recovered'.  This recovered file can be
        /// opened as a normal <see cref="BPlusTree{TKey, TValue}"/> to view it's contents.  During the restore it is possible that
        /// a single Key was found multiple times, in this case the first occurrence found will be used.
        /// </remarks>
        /// <param name="options"> The options normally used to create the <see cref="BPlusTree{TKey, TValue}"/> instance </param>
        /// <returns>Returns 0 on failure, or the number of records successfully retrieved from the original file </returns>
        public static int RecoverFile(Options options)
        {
            int    recoveredCount = 0;
            string filename       = options.FileName;

            if (String.IsNullOrEmpty(filename))
            {
                throw new InvalidConfigurationValueException("FileName", "The FileName property was not specified.");
            }
            if (!File.Exists(filename))
            {
                throw new InvalidConfigurationValueException("FileName", "The FileName specified does not exist.");
            }
            if (options.StorageType != StorageType.Disk)
            {
                throw new InvalidConfigurationValueException("StorageType", "The storage type is not set to 'Disk'.");
            }

            int    ix          = 0;
            string tmpfilename = filename + ".recovered";

            while (File.Exists(tmpfilename))
            {
                tmpfilename = filename + ".recovered" + ix++;
            }

            try
            {
                BPlusTreeOptions <TKey, TValue> tmpoptions = options.Clone();
                tmpoptions.CreateFile     = CreatePolicy.Always;
                tmpoptions.FileName       = tmpfilename;
                tmpoptions.LockingFactory = new LockFactory <IgnoreLocking>();

                using (BPlusTree <TKey, TValue> tmpFile = new BPlusTree <TKey, TValue>(tmpoptions))
                {
                    BulkInsertOptions bulkOptions = new BulkInsertOptions();
                    bulkOptions.DuplicateHandling = DuplicateHandling.LastValueWins;

                    recoveredCount = tmpFile.BulkInsert(RecoveryScan(options, FileShare.None), bulkOptions);
                }
            }
            finally
            {
                if (recoveredCount == 0 && File.Exists(tmpfilename))
                {
                    File.Delete(tmpfilename);
                }
            }

            if (recoveredCount > 0)
            {
                ix = 0;
                string backupName = filename + ".deleted";
                while (File.Exists(backupName))
                {
                    backupName = filename + ".deleted" + ix++;
                }

                File.Move(filename, backupName);
                try { File.Move(tmpfilename, filename); }
                catch
                {
                    File.Move(backupName, filename);
                    throw;
                }
            }

            return(recoveredCount);
        }
Example #6
0
 public NodeCacheNormal(BPlusTreeOptions <TKey, TValue> options) : base(options)
 {
     _keepAlive = options.CreateCacheKeepAlive();
     _cache     = new Dictionary <NodeHandle, Utils.WeakReference <CacheEntry> >();
     _cacheLock = new ReaderWriterLocking();
 }
 static BPlusTreeOptions <TKey, TValue> Fix(BPlusTreeOptions <TKey, TValue> options)
 {
     return(options);
 }
 public NodeCacheNone(BPlusTreeOptions <TKey, TValue> options)
     : base(Fix(options))
 {
     _lock = new ReaderWriterLocking();
     _list = new Dictionary <IStorageHandle, ILockStrategy>();
 }
Example #9
0
        public BPlusTree(BPlusTreeOptions <TKey, TValue> ioptions)
        {
            bool fileExists =
                ioptions.StorageType == StorageType.Disk &&
                ioptions.CreateFile != CreatePolicy.Always &&
                File.Exists(ioptions.FileName) &&
                new FileInfo(ioptions.FileName).Length > 0;

            _options      = ioptions.Clone();
            _selfLock     = _options.CallLevelLock;
            _keyComparer  = _options.KeyComparer;
            _itemComparer = new ElementComparer(_keyComparer);

            switch (_options.CachePolicy)
            {
            case CachePolicy.All: _storage = new NodeCacheFull(_options); break;

            case CachePolicy.Recent: _storage = new NodeCacheNormal(_options); break;

            case CachePolicy.None: _storage = new NodeCacheNone(_options); break;

            default: throw new InvalidConfigurationValueException("CachePolicy");
            }

            try
            {
                _storage.Load();
            }
            catch
            {
                _storage.Dispose();
                throw;
            }

            if (_options.LogFile != null && !_options.ReadOnly)
            {
                if (_options.ExistingLogAction == ExistingLogAction.Truncate ||
                    _options.ExistingLogAction == ExistingLogAction.Default && !fileExists)
                {
                    _options.LogFile.TruncateLog();
                }
                else if (_options.LogFile.Size > 0 && (
                             _options.ExistingLogAction == ExistingLogAction.Replay ||
                             _options.ExistingLogAction == ExistingLogAction.ReplayAndCommit ||
                             (_options.ExistingLogAction == ExistingLogAction.Default && fileExists)
                             ))
                {
                    bool commit = (_options.ExistingLogAction == ExistingLogAction.ReplayAndCommit ||
                                   (_options.ExistingLogAction == ExistingLogAction.Default && fileExists));

                    bool merge = false;
                    if (_options.StorageType == StorageType.Disk)
                    {
                        merge = new FileInfo(_options.FileName).Length < _options.LogFile.Size;
                    }

                    if (merge) // log data is larger than we are...
                    {
                        BulkInsertOptions opts = new BulkInsertOptions();
                        opts.CommitOnCompletion = commit;
                        opts.DuplicateHandling  = DuplicateHandling.LastValueWins;
                        opts.InputIsSorted      = true;
                        opts.ReplaceContents    = true;
                        BulkInsert(
                            _options.LogFile.MergeLog(_options.KeyComparer,
                                                      File.Exists(ioptions.FileName) ? EnumerateFile(ioptions) : new KeyValuePair <TKey, TValue> [0]),
                            opts
                            );
                    }
                    else
                    {
                        _options.LogFile.ReplayLog(this);
                        if (commit) //Now commit the recovered changes
                        {
                            Commit();
                        }
                    }
                }
            }

            var nodeStoreWithCount = _storage.Storage as INodeStoreWithCount;

            if (nodeStoreWithCount != null)
            {
                _count    = nodeStoreWithCount.Count;
                _hasCount = _count >= 0;
            }
        }
Example #10
0
 public NodeCacheFull(BPlusTreeOptions <TKey, TValue> options)
     : base(options)
 {
 }
Example #11
0
 public NodeCacheNormal(BPlusTreeOptions <TKey, TValue> options) : base(options)
 {
     _keepAlive = new ObjectKeepAlive(options.CacheKeepAliveMinimumHistory, options.CacheKeepAliveMaximumHistory, TimeSpan.FromMilliseconds(options.CacheKeepAliveTimeout));
     _cache     = new Dictionary <NodeHandle, WeakReference <CacheEntry> >();
     _cacheLock = new SimpleReadWriteLocking();
 }