public void Open() { if (_dbLock == null) { throw new ObjectDisposedException("Database was closed and can not be reopened"); } _dbLock.EnterWriteLock(); try { if (_manifest != null) { throw new InvalidOperationException("Already had manifest for database. Did you already open it?"); } if (_memCache != 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}"); } Directory.Refresh(); Log.Warn($"Extracted bedrock world and set new DB directory to: {Directory.FullName}"); } // Verify that directory exists if (!Directory.Exists) { Directory.Create(); Directory.Refresh(); } if (!File.Exists(GetCurrentFileName())) { if (!_createIfMissing) { var notFoundException = new DirectoryNotFoundException(Directory.FullName); Log.Error(notFoundException); throw notFoundException; } // Create new MANIFEST var manifest = new Manifest(Directory); manifest.CurrentVersion = new Version() { Comparator = "leveldb.BytewiseComparator", LogNumber = 1, PreviousLogNumber = 0, NextFileNumber = 2, LastSequenceNumber = 0 }; var manifestFileInfo = new FileInfo(GetManifestFileName(1)); if (manifestFileInfo.Exists) { throw new PanicException($"Trying to create database, but found existing MANIFEST file at {manifestFileInfo.FullName}. Aborting."); } using var writer = new LogWriter(manifestFileInfo); manifest.Save(writer); manifest.Close(); // Create new CURRENT text file and store manifest filename in it using StreamWriter current = File.CreateText(GetCurrentFileName()); current.WriteLine(manifestFileInfo.Name); current.Close(); // Done and created } Directory.Refresh(); // If this has been manipulated on the way, this is really needed. // Read Manifest into memory string manifestFilename = GetManifestFileNameFromCurrent(); Log.Debug($"Reading manifest from {manifestFilename}"); using (var reader = new LogReader(new FileInfo(manifestFilename))) { _manifest = new Manifest(Directory); _manifest.Load(reader); } // Read current log var logFile = new FileInfo(GetLogFileName(_manifest.CurrentVersion.LogNumber)); Log.Debug($"Reading log from {logFile.FullName}"); using (var reader = new LogReader(logFile)) { _memCache = new MemCache(); _memCache.Load(reader); } // Append mode _log = new LogWriter(logFile); } finally { _dbLock.ExitWriteLock(); } // We do this on startup. It will rotate the log files and create // level 0 tables. However, we want to use into reusing the logs. CompactMemCache(); CleanOldFiles(); _compactTimer = new Timer(state => DoCompaction(), null, 300, 300); }
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); } }