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);
        }
Exemple #2
0
        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);
            }
        }