public void Load(LogReader reader) { if (CurrentVersion != null) { return; } CurrentVersion = ReadVersionEdit(reader); Print(CurrentVersion); foreach (var level in CurrentVersion.NewFiles) // Search all levels for file with matching index { foreach (FileMetadata tbl in level.Value) { if (Log.IsDebugEnabled) { Log.Debug($"Found table file for key in level {level.Key} in file={tbl.FileNumber}"); } Table tableReader = tbl.Table; if (tableReader == null) { FileInfo f = new FileInfo(Path.Combine(_baseDirectory.FullName, $"{tbl.FileNumber:000000}.ldb")); if (!f.Exists) { throw new Exception($"Could not find table {f.FullName}"); } tableReader = new Table(f); tbl.Table = tableReader; } } } }
public void Close() { var tableFiles = CurrentVersion.NewFiles; CurrentVersion = null; foreach (var level in tableFiles) // Search all levels for file with matching index { foreach (FileMetadata tbl in level.Value) { tbl.Table?.Dispose(); tbl.Table = null; } } }
public VersionEdit ReadVersionEdit(LogReader logReader) { string comparator = null; ulong? logNumber = null; ulong? previousLogNumber = null; ulong? nextFileNumber = null; ulong? lastSequenceNumber = null; VersionEdit finalVersion = new VersionEdit(); while (true) { Record record = logReader.ReadRecord(); if (record.LogRecordType != LogRecordType.Full) { break; } var reader = new SpanReader(record.Data); VersionEdit versionEdit = new VersionEdit(); while (!reader.Eof) { LogTagType logTag = (LogTagType)reader.ReadVarLong(); switch (logTag) { case LogTagType.Comparator: { versionEdit.Comparator = reader.ReadLengthPrefixedString(); break; } case LogTagType.LogNumber: { versionEdit.LogNumber = reader.ReadVarLong(); break; } case LogTagType.NextFileNumber: { versionEdit.NextFileNumber = reader.ReadVarLong(); break; } case LogTagType.LastSequence: { versionEdit.LastSequenceNumber = reader.ReadVarLong(); break; } case LogTagType.CompactPointer: { int level = (int)reader.ReadVarLong(); var internalKey = reader.ReadLengthPrefixedBytes(); versionEdit.CompactPointers[level] = internalKey.ToArray(); break; } case LogTagType.DeletedFile: { int level = (int)reader.ReadVarLong(); ulong fileNumber = reader.ReadVarLong(); if (!versionEdit.DeletedFiles.ContainsKey(level)) { versionEdit.DeletedFiles[level] = new List <ulong>(); } versionEdit.DeletedFiles[level].Add(fileNumber); if (!finalVersion.DeletedFiles.ContainsKey(level)) { finalVersion.DeletedFiles[level] = new List <ulong>(); } finalVersion.DeletedFiles[level].Add(fileNumber); break; } case LogTagType.NewFile: { int level = (int)reader.ReadVarLong(); ulong fileNumber = reader.ReadVarLong(); ulong fileSize = reader.ReadVarLong(); var smallest = reader.ReadLengthPrefixedBytes(); var largest = reader.ReadLengthPrefixedBytes(); FileMetadata fileMetadata = new FileMetadata(); fileMetadata.FileNumber = fileNumber; fileMetadata.FileSize = fileSize; fileMetadata.SmallestKey = smallest.ToArray(); fileMetadata.LargestKey = largest.ToArray(); if (!versionEdit.NewFiles.ContainsKey(level)) { versionEdit.NewFiles[level] = new List <FileMetadata>(); } versionEdit.NewFiles[level].Add(fileMetadata); if (!finalVersion.NewFiles.ContainsKey(level)) { finalVersion.NewFiles[level] = new List <FileMetadata>(); } finalVersion.NewFiles[level].Add(fileMetadata); break; } case LogTagType.PrevLogNumber: { versionEdit.PreviousLogNumber = reader.ReadVarLong(); break; } default: { throw new ArgumentOutOfRangeException($"Unknown tag={logTag}"); } } } versionEdit.CompactPointers = versionEdit.CompactPointers.Count == 0 ? null : versionEdit.CompactPointers; versionEdit.DeletedFiles = versionEdit.DeletedFiles.Count == 0 ? null : versionEdit.DeletedFiles; versionEdit.NewFiles = versionEdit.NewFiles.Count == 0 ? null : versionEdit.NewFiles; comparator = versionEdit.Comparator ?? comparator; logNumber = versionEdit.LogNumber ?? logNumber; previousLogNumber = versionEdit.PreviousLogNumber ?? previousLogNumber; nextFileNumber = versionEdit.NextFileNumber ?? nextFileNumber; lastSequenceNumber = versionEdit.LastSequenceNumber ?? lastSequenceNumber; } // Clean files List <ulong> deletedFiles = new List <ulong>(); foreach (var versionDeletedFile in finalVersion.DeletedFiles.Values) { deletedFiles.AddRange(versionDeletedFile); } foreach (var levelKvp in finalVersion.NewFiles) { foreach (var newFile in levelKvp.Value.ToArray()) { if (deletedFiles.Contains(newFile.FileNumber)) { levelKvp.Value.Remove(newFile); } } } finalVersion.NewFiles = finalVersion.NewFiles.OrderBy(kvp => kvp.Key).ToDictionary(pair => pair.Key, pair => pair.Value); finalVersion.Comparator = comparator; finalVersion.LogNumber = logNumber; finalVersion.PreviousLogNumber = previousLogNumber; finalVersion.NextFileNumber = nextFileNumber; finalVersion.LastSequenceNumber = lastSequenceNumber; return(finalVersion); }
public void Open() { if (_manifest != null) { throw new InvalidOperationException("Already had manifest for database. Did you already open it?"); } if (_newMemCache != null) { throw new InvalidOperationException("Already had memory cache for database. Did you already open it?"); } if (Directory.Name.EndsWith(".mcworld")) { // Exported from MCPE. Unpack to temp Log.Debug($"Opening directory: {Directory.Name}"); var originalFile = Directory; string newDirPath = Path.Combine(Path.GetTempPath(), Directory.Name); Directory = new DirectoryInfo(Path.Combine(newDirPath, "db")); if (!Directory.Exists || originalFile.LastWriteTimeUtc > Directory.LastWriteTimeUtc) { ZipFile.ExtractToDirectory(originalFile.FullName, newDirPath, true); Log.Warn($"Created new temp directory: {Directory.FullName}"); } Log.Warn($"Extracted bedrock world and set new DB directory to: {Directory.FullName}"); } // Verify that directory exists if (!Directory.Exists) { if (!CreateIfMissing) { throw new DirectoryNotFoundException(Directory.Name); } Directory.Create(); // Create new MANIFEST VersionEdit newVersion = new VersionEdit(); newVersion.NextFileNumber = 1; newVersion.Comparator = "leveldb.BytewiseComparator"; // Create new CURRENT text file and store manifest filename in it using (var manifestStream = File.CreateText($@"{Path.Combine(Directory.FullName, "CURRENT")}")) { manifestStream.WriteLine($"MANIFEST-{newVersion.NextFileNumber++:000000}"); manifestStream.Close(); } // Done } // Read Manifest into memory string manifestFilename; using (var currentStream = File.OpenText($@"{Path.Combine(Directory.FullName, "CURRENT")}")) { manifestFilename = currentStream.ReadLine(); currentStream.Close(); } Log.Debug($"Reading manifest from {Path.Combine(Directory.FullName, manifestFilename)}"); using (var reader = new LogReader(new FileInfo($@"{Path.Combine(Directory.FullName, manifestFilename)}"))) { _manifest = new Manifest(Directory); _manifest.Load(reader); } // Read current log //TODO: remove unit-test-stuff var logFileName = Path.Combine(Directory.FullName, $"{_manifest.CurrentVersion.LogNumber + 1:000000}.log"); FileInfo f = new FileInfo(logFileName); if (!f.Exists) { f = new FileInfo(Path.Combine(Directory.FullName, $"{_manifest.CurrentVersion.LogNumber:000000}.log")); } using (var reader = new LogReader(f)) { _newMemCache = new MemCache(); _newMemCache.Load(reader); } }