Пример #1
0
        public void Truncate()
        {
            _currentJournaledMemTable.Close();
            TableManager.Default.Close(this);
            foreach (var pair in _secondaryIndexes)
            {
                pair.Value.Close(FastClose);
            }

            string basePath = Path.GetFullPath(Manifest.BaseFileName);

            foreach (string file in Directory.GetFiles(basePath, "*.*", SearchOption.AllDirectories))
            {
                Helper.DeleteFile(file, false, (msg) => { Manifest.LogMessage(msg); });
            }
            foreach (string dir in Directory.GetDirectories(basePath, "*.*", SearchOption.AllDirectories))
            {
                Helper.DeleteFolder(dir, false, (msg) => { Manifest.LogMessage(msg); });
            }

            _manifest = new Manifest(basePath);
            _currentJournaledMemTable = new JournaledMemTable(_manifest.BaseFileName, _manifest.CurrentVersion(0));
            _cache            = new RazorCache();
            _secondaryIndexes = new Dictionary <string, KeyValueStore>(StringComparer.OrdinalIgnoreCase);

            Manifest.LogMessage("Database Truncated.");
        }
Пример #2
0
        public static IEnumerable <KeyValuePair <Key, Value> > Enumerate(int level, RazorCache rzrCache, string baseFileName, ManifestImmutable mft, Key key)
        {
            var enumerator = new TableEnumerator(level, rzrCache, baseFileName, mft, key);

            while (enumerator.MoveNext())
            {
                yield return(enumerator.Current);
            }
        }
Пример #3
0
 public SortedBlockTable(RazorCache cache, string baseFileName, int level, int version)
 {
     PerformanceCounters.SBTConstructed.Increment();
     _baseFileName = baseFileName;
     _level        = level;
     _version      = version;
     _cache        = cache;
     _path         = Config.SortedBlockTableFile(baseFileName, level, version);
     ReadMetadata();
 }
Пример #4
0
        public static IEnumerable <PageRecord> MergeTables(RazorCache cache, Manifest mf, int destinationLevel, IEnumerable <PageRef> tableSpecs, ExceptionHandling exceptionHandling, Action <string> logger)
        {
            var orderedTableSpecs         = tableSpecs.OrderByPagePriority();
            var outputTables              = new List <PageRecord>();
            SortedBlockTableWriter writer = null;

            Key firstKey = new Key();
            Key lastKey  = new Key();
            Key maxKey   = new Key(); // Maximum key we can span with this table to avoid covering more than 10 pages in the destination

            Action <KeyValuePair <Key, Value> > OpenPage = (pair) => {
                writer = new SortedBlockTableWriter(mf.BaseFileName, destinationLevel, mf.NextVersion(destinationLevel));

                firstKey = pair.Key;
                using (var m = mf.GetLatestManifest()) {
                    maxKey = m.FindSpanningLimit(destinationLevel + 1, firstKey);
                }
            };
            Action ClosePage = () => {
                writer.Close();
                outputTables.Add(new PageRecord(destinationLevel, writer.Version, firstKey, lastKey));
                writer = null;
            };

            try {
                foreach (var pair in EnumerateMergedTablesPreCached(cache, mf.BaseFileName, orderedTableSpecs, exceptionHandling, logger))
                {
                    if (writer == null)
                    {
                        OpenPage(pair);
                    }
                    if (writer.WrittenSize >= Config.MaxSortedBlockTableSize || (!maxKey.IsEmpty && pair.Key.CompareTo(maxKey) >= 0))
                    {
                        ClosePage();
                    }
                    if (writer == null)
                    {
                        OpenPage(pair);
                    }
                    writer.WritePair(pair.Key, pair.Value);
                    lastKey = pair.Key;
                }
            } finally {
                if (writer != null)
                {
                    ClosePage();
                }
            }

            return(outputTables);
        }
Пример #5
0
        public KeyValueStore(string baseFileName, RazorCache cache)
        {
            if (!Directory.Exists(baseFileName))
            {
                Directory.CreateDirectory(baseFileName);
            }
            _manifest        = new Manifest(baseFileName);
            _manifest.Logger = Config.Logger;

            int memTableVersion = _manifest.CurrentVersion(0);

            // Check for a previously aborted journal rotation
            CheckForIncompleteJournalRotation(baseFileName, memTableVersion);
            // Create new journal for this run (and potentially load from disk, if there was data loaded previously)
            _currentJournaledMemTable = new JournaledMemTable(_manifest.BaseFileName, memTableVersion);
            _cache = cache == null ? new RazorCache() : cache;
        }
Пример #6
0
        public static bool Lookup(string baseFileName, int level, int version, RazorCache cache, Key key, out Value value, ExceptionHandling exceptionHandling, Action <string> logger)
        {
            PerformanceCounters.SBTLookup.Increment();
            SortedBlockTable sbt = new SortedBlockTable(cache, baseFileName, level, version);

            try {
                byte[] lastScanKey;
                int    dataBlockNum = FindBlockForKey(baseFileName, level, version, cache, key, out lastScanKey);
                if (dataBlockNum >= 0 && dataBlockNum < sbt._dataBlocks)
                {
                    byte[] block = sbt.ReadBlock(LocalThreadAllocatedBlock(), dataBlockNum, lastScanKey);
                    return(sbt.ScanBlockForKey(block, key, out value));
                }
            } finally {
                sbt.Close();
            }
            value = Value.Empty;
            return(false);
        }
Пример #7
0
        public TableEnumerator(int level, RazorCache rzrCache, string baseFileName, ManifestImmutable mft, Key key)
        {
            Cache           = rzrCache;
            BaseFileName    = baseFileName;
            ActiveManifest  = mft;
            StartKey        = key;
            Level           = level;
            StopEnumerating = false;

            var firstPage = ActiveManifest.FindPageForIndex(level, 0);

            if (firstPage != null && key.CompareTo(firstPage.FirstKey) < 0)
            {
                StartPageIndex = 0;
            }
            else
            {
                StartPageIndex = ActiveManifest.FindPageIndexForKey(Level, StartKey);
            }

            InitEnumerator();
        }
Пример #8
0
        public static void RunTableMergePass(KeyValueStore kvStore)
        {
            try {
                Interlocked.Increment(ref kvStore.mergeCount);

                lock (kvStore.mergeLock) {
                    RazorCache cache    = kvStore.Cache;
                    Manifest   manifest = kvStore.Manifest;

                    while (true)
                    {
                        bool mergedDuringLastPass = false;
                        using (var manifestInst = kvStore.Manifest.GetLatestManifest()) {
                            // Handle level 0 (merge all pages)
                            if (manifestInst.GetNumPagesAtLevel(0) >= Config.MaxPagesOnLevel(0))
                            {
                                mergedDuringLastPass = true;
                                var inputPageRecords = manifestInst.GetPagesAtLevel(0).OrderBy(p => p.Version).ToList();
                                var startKey         = inputPageRecords.Min(p => p.FirstKey);
                                var endKey           = inputPageRecords.Max(p => p.LastKey);
                                var mergePages       = manifestInst.FindPagesForKeyRange(1, startKey, endKey).AsPageRefs().ToList();
                                var allInputPages    = inputPageRecords.AsPageRefs().Concat(mergePages).ToList();

                                var outputPages = SortedBlockTable.MergeTables(cache, manifest, 1, allInputPages, ExceptionHandling.ThrowAll, null).ToList();
                                manifest.ModifyPages(outputPages, allInputPages);

                                manifest.LogMessage("Merge Level 0 => InputPages: {0} OutputPages:{1}",
                                                    string.Join(",", allInputPages.Select(p => string.Format("{0}-{1}", p.Level, p.Version)).ToArray()),
                                                    string.Join(",", outputPages.Select(p => string.Format("{0}-{1}", p.Level, p.Version)).ToArray())
                                                    );
                            }
                            // handle the rest of the levels (merge only one page upwards)
                            for (int level = 1; level < manifestInst.NumLevels - 1; level++)
                            {
                                if (manifestInst.GetNumPagesAtLevel(level) >= Config.MaxPagesOnLevel(level))
                                {
                                    mergedDuringLastPass = true;
                                    var inputPage        = manifest.NextMergePage(level);
                                    var mergePages       = manifestInst.FindPagesForKeyRange(level + 1, inputPage.FirstKey, inputPage.LastKey).ToList();
                                    var inputPageRecords = mergePages.Concat(new PageRecord[] { inputPage });
                                    var allInputPages    = inputPageRecords.AsPageRefs().ToList();
                                    var outputPages      = SortedBlockTable.MergeTables(cache, manifest, level + 1, allInputPages, ExceptionHandling.ThrowAll, null);

                                    // Notify if a merge happened, implemented for testing primarily
                                    if (kvStore.MergeCallback != null)
                                    {
                                        kvStore.MergeCallback(level, inputPageRecords, outputPages);
                                    }
                                    manifest.ModifyPages(outputPages, allInputPages);

                                    manifest.LogMessage("Merge Level >0 => InputPages: {0} OutputPages:{1}",
                                                        string.Join(",", allInputPages.Select(p => string.Format("{0}-{1}", p.Level, p.Version)).ToArray()),
                                                        string.Join(",", outputPages.Select(p => string.Format("{0}-{1}", p.Level, p.Version)).ToArray())
                                                        );
                                }
                            }
                        }

                        // No more merging is needed, we are finished with this pass
                        if (!mergedDuringLastPass)
                        {
                            return;
                        }
                    }
                }
            } finally {
                Interlocked.Decrement(ref kvStore.mergeCount);
            }
        }
Пример #9
0
        public static IEnumerable <KeyValuePair <Key, Value> > EnumerateMergedTablesPreCached(RazorCache cache, string baseFileName, IEnumerable <PageRef> tableSpecs, ExceptionHandling exceptionHandling, Action <string> logger)
        {
            PerformanceCounters.SBTEnumerateMergedTablesPrecached.Increment();
            var tables = tableSpecs
                         .Select(pageRef => new SortedBlockTable(cache, baseFileName, pageRef.Level, pageRef.Version))
                         .ToList();

            try {
                foreach (var pair in MergeEnumerator.Merge(tables.Select(t => t.Enumerate().ToList().AsEnumerable()), t => t.Key))
                {
                    yield return(pair);
                }
            } finally {
                tables.ForEach(t => t.Close());
            }
        }
Пример #10
0
        public IEnumerable <RawRecord> EnumerateFromKeyRaw(RazorCache indexCache, Key key)
        {
            if (!FileExists)
            {
                yield break;
            }

            int startingBlock;

            if (key.Length == 0)
            {
                startingBlock = 0;
            }
            else
            {
                startingBlock = FindBlockForKey(_baseFileName, _level, _version, indexCache, key, out _lastScanKey);
                if (startingBlock < 0)
                {
                    startingBlock = 0;
                }
            }
            if (startingBlock < _dataBlocks)
            {
                byte[] allocBlockA  = new byte[Config.SortedBlockSize];
                byte[] allocBlockB  = new byte[Config.SortedBlockSize];
                byte[] currentBlock = allocBlockA;

                var asyncResult = BeginReadBlock(currentBlock, startingBlock);

                try {
                    for (int i = startingBlock; i < _dataBlocks; i++)
                    {
                        // wait on last block read to complete so we can start processing the data
                        byte[] block = EndReadBlock(asyncResult);
                        asyncResult = null;

                        // Go ahead and kick off the next block read asynchronously while we parse the last one
                        if (i < _dataBlocks)
                        {
                            SwapBlocks(allocBlockA, allocBlockB, ref currentBlock); // swap the blocks so we can issue another disk i/o
                            asyncResult = BeginReadBlock(currentBlock, i + 1);
                        }

                        int offset = FormatVersion < 2 ? 2 : 02; // handle old format with 2 bytes for offset to treehead

                        // On the first block, we need to seek to the key first (if we don't have an empty key)
                        if (i == startingBlock && key.Length != 0)
                        {
                            while (offset >= 0)
                            {
                                var rec = ReadRawRecord(ref block, ref offset);
                                if (rec.Key.CompareTo(key) >= 0)
                                {
                                    yield return(rec);

                                    break;
                                }
                            }
                        }

                        // Now loop through the rest of the block
                        while (offset >= 0)
                        {
                            yield return(ReadRawRecord(ref block, ref offset));
                        }
                    }
                } finally {
                    if (asyncResult != null)
                    {
                        EndReadBlock(asyncResult);
                    }
                }
            }
        }
Пример #11
0
        private static int FindBlockForKey(string baseFileName, int level, int version, RazorCache indexCache, Key key, out byte[] baseKey)
        {
            Key[] index        = indexCache.GetBlockTableIndex(baseFileName, level, version);
            int   dataBlockNum = Array.BinarySearch(index, key);

            if (dataBlockNum < 0)
            {
                dataBlockNum = ~dataBlockNum - 1;
            }

            baseKey = (dataBlockNum > -1 && dataBlockNum < index.Length) ? index[dataBlockNum].InternalBytes : Key.Empty.InternalBytes;
            return(dataBlockNum);
        }