public SQLitePersistentStorage(
            string workingFolderPath,
            string solutionFilePath,
            string databaseFile,
            IDisposable dbOwnershipLock,
            IPersistentStorageFaultInjector faultInjectorOpt)
            : base(workingFolderPath, solutionFilePath, databaseFile)
        {
            _dbOwnershipLock  = dbOwnershipLock;
            _faultInjectorOpt = faultInjectorOpt;

            _solutionAccessor = new SolutionAccessor(this);
            _projectAccessor  = new ProjectAccessor(this);
            _documentAccessor = new DocumentAccessor(this);

            _select_star_from_string_table     = $@"select * from {StringInfoTableName}";
            _insert_into_string_table_values_0 = $@"insert into {StringInfoTableName}(""{DataColumnName}"") values (?)";
            _select_star_from_string_table_where_0_limit_one = $@"select * from {StringInfoTableName} where (""{DataColumnName}"" = ?) limit 1";

            // Create a queue to batch up requests to flush.  We'll won't flush more than every FlushAllDelayMS. The
            // actual information in the queue isn't relevant, so we pass in an equality comparer to just keep it down
            // to storing a single piece of data.
            _flushQueue = new AsyncBatchingWorkQueue <bool>(
                TimeSpan.FromMilliseconds(FlushAllDelayMS),
                FlushInMemoryDataToDiskIfNotShutdownAsync,
                EqualityComparer <bool> .Default,
                asyncListener: null,
                _shutdownTokenSource.Token);
        }
Exemplo n.º 2
0
        public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath)
        {
            faultInjector?.OnNewConnection();

            // Allocate dictionary before doing any sqlite work.  That way if it throws
            // we don't have to do any additional cleanup.
            var queryToStatement = new Dictionary <string, SqlStatement>();

            // Use SQLITE_OPEN_NOMUTEX to enable multi-thread mode, where multiple connections can be used provided each
            // one is only used from a single thread at a time.
            // see https://sqlite.org/threadsafe.html for more detail
            var flags  = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE | OpenFlags.SQLITE_OPEN_NOMUTEX;
            var handle = NativeMethods.sqlite3_open_v2(databasePath, (int)flags, vfs: null, out var result);

            if (result != Result.OK)
            {
                handle.Dispose();
                throw new SqlException(result, $"Could not open database file: {databasePath} ({result})");
            }

            try
            {
                NativeMethods.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds);
                return(new SqlConnection(handle, faultInjector, queryToStatement));
            }
            catch
            {
                // If we failed to create connection, ensure that we still release the sqlite
                // handle.
                handle.Dispose();
                throw;
            }
        }
Exemplo n.º 3
0
        public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath)
        {
            faultInjector?.OnNewConnection();

            // Allocate dictionary before doing any sqlite work.  That way if it throws
            // we don't have to do any additional cleanup.
            var queryToStatement = new Dictionary <string, SqlStatement>();

            // Use SQLITE_OPEN_NOMUTEX to enable multi-thread mode, where multiple connections can
            // be used provided each one is only used from a single thread at a time.
            //
            // Use SHAREDCACHE so that we can have an in-memory DB that we dump our writes into.  We
            // need SHAREDCACHE so that all connections see that same in-memory DB.  This also
            // requires OPEN_URI since we need a `file::memory:` uri for them all to refer to.
            //
            // see https://sqlite.org/threadsafe.html for more detail
            var flags = OpenFlags.SQLITE_OPEN_CREATE |
                        OpenFlags.SQLITE_OPEN_READWRITE |
                        OpenFlags.SQLITE_OPEN_NOMUTEX |
                        OpenFlags.SQLITE_OPEN_SHAREDCACHE |
                        OpenFlags.SQLITE_OPEN_URI;
            var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null);

            if (result != Result.OK)
            {
                throw new SqlException(result, $"Could not open database file: {databasePath} ({result})");
            }

            Contract.ThrowIfNull(handle);

            try
            {
                raw.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds);
                var connection = new SqlConnection(handle, faultInjector, queryToStatement);

                // Attach (creating if necessary) a singleton in-memory write cache to this connection.
                //
                // From: https://www.sqlite.org/sharedcache.html Enabling shared-cache for an in-memory
                // database allows two or more database connections in the same process to have access
                // to the same in-memory database. An in-memory database in shared cache is
                // automatically deleted and memory is reclaimed when the last connection to that
                // database closes.
                //
                // Using `cache=shared as writecache` at the end ensures all connections see the same db
                // and the same data when reading and writing.  i.e. if one connection writes data to
                // this, another connection will see that data when reading.  Without this, each
                // connection would get their own private memory db independent of all other
                // connections.
                connection.ExecuteCommand($"attach database 'file::memory:?cache=shared' as {Database.WriteCache.GetName()};");

                return(connection);
            }
            catch
            {
                // If we failed to create connection, ensure that we still release the sqlite
                // handle.
                raw.sqlite3_close(handle);
                throw;
            }
        }
 public SQLitePersistentStorageService(
     IPersistentStorageLocationService locationService,
     IPersistentStorageFaultInjector faultInjector)
     : this(locationService)
 {
     _faultInjectorOpt = faultInjector;
 }
Exemplo n.º 5
0
        internal IPersistentStorage GetStorage(
            Solution solution, IPersistentStorageFaultInjector faultInjectorOpt = null)
        {
            var storage = GetStorageService(faultInjectorOpt).GetStorage(solution);

            Assert.NotEqual(NoOpPersistentStorage.Instance, storage);
            return(storage);
        }
 public SQLitePersistentStorageService(
     IOptionService optionService,
     IPersistentStorageLocationService locationService,
     ISolutionSizeTracker solutionSizeTracker,
     IPersistentStorageFaultInjector faultInjector)
     : this(optionService, locationService, solutionSizeTracker)
 {
     _faultInjectorOpt = faultInjector;
 }
Exemplo n.º 7
0
 private SqlConnection(sqlite3 handle, IPersistentStorageFaultInjector faultInjector, Dictionary <string, SqlStatement> queryToStatement)
 {
     // This constructor avoids allocations since failure (e.g. OutOfMemoryException) would
     // leave the object partially-constructed, and the finalizer would run later triggering
     // a crash.
     _handle           = handle;
     _faultInjector    = faultInjector;
     _queryToStatement = queryToStatement;
 }
Exemplo n.º 8
0
 public SQLitePersistentStorage(
     IOptionService optionService,
     string workingFolderPath,
     string solutionFilePath,
     string databaseFile,
     Action <AbstractPersistentStorage> disposer,
     IPersistentStorageFaultInjector faultInjectorOpt)
     : base(optionService, workingFolderPath, solutionFilePath, databaseFile, disposer)
 {
     _faultInjectorOpt = faultInjectorOpt;
     _solutionAccessor = new SolutionAccessor(this);
     _projectAccessor  = new ProjectAccessor(this);
     _documentAccessor = new DocumentAccessor(this);
 }
Exemplo n.º 9
0
        public SQLitePersistentStorage(
            string workingFolderPath,
            string solutionFilePath,
            string databaseFile,
            IDisposable dbOwnershipLock,
            IPersistentStorageFaultInjector faultInjectorOpt)
            : base(workingFolderPath, solutionFilePath, databaseFile)
        {
            _dbOwnershipLock  = dbOwnershipLock;
            _faultInjectorOpt = faultInjectorOpt;

            _solutionAccessor = new SolutionAccessor(this);
            _projectAccessor  = new ProjectAccessor(this);
            _documentAccessor = new DocumentAccessor(this);
        }
Exemplo n.º 10
0
        public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath)
        {
            faultInjector?.OnNewConnection();

            var flags  = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE;
            var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null);

            if (result != Result.OK)
            {
                throw new SqlException(result, $"Could not open database file: {databasePath} ({result})");
            }

            Contract.ThrowIfNull(handle);

            raw.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds);

            return(new SqlConnection(faultInjector, handle));
        }
        internal IChecksummedPersistentStorage GetStorageFromKey(
            Workspace workspace, SolutionKey solutionKey, IPersistentStorageFaultInjector faultInjectorOpt = null)
        {
            // If we handed out one for a previous test, we need to shut that down first
            _storageService?.GetTestAccessor().Shutdown();
            var locationService = new MockPersistentStorageLocationService(solutionKey.Id, _persistentFolder.Path);

            _storageService = GetStorageService(locationService, faultInjectorOpt);
            var storage = _storageService.GetStorage(workspace, solutionKey, checkBranchId: true);

            // If we're injecting faults, we expect things to be strange
            if (faultInjectorOpt == null)
            {
                Assert.NotEqual(NoOpPersistentStorage.Instance, storage);
            }

            return(storage);
        }
Exemplo n.º 12
0
        public SQLitePersistentStorage(
            string workingFolderPath,
            string solutionFilePath,
            string databaseFile,
            IDisposable dbOwnershipLock,
            IPersistentStorageFaultInjector faultInjectorOpt)
            : base(workingFolderPath, solutionFilePath, databaseFile)
        {
            _dbOwnershipLock  = dbOwnershipLock;
            _faultInjectorOpt = faultInjectorOpt;

            _solutionAccessor = new SolutionAccessor(this);
            _projectAccessor  = new ProjectAccessor(this);
            _documentAccessor = new DocumentAccessor(this);

            _select_star_from_0     = $@"select * from ""{StringInfoTableName}""";
            _insert_into_0_1_values = $@"insert into ""{StringInfoTableName}""(""{DataColumnName}"") values (?)";
            _select_star_from_0_where_1_limit_one = $@"select * from ""{StringInfoTableName}"" where (""{DataColumnName}"" = ?) limit 1";
        }
Exemplo n.º 13
0
        public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath)
        {
            faultInjector?.OnNewConnection();

            // Enable shared cache so that multiple connections inside of same process share cache
            // see https://sqlite.org/threadsafe.html for more detail
            var flags  = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE | OpenFlags.SQLITE_OPEN_NOMUTEX | OpenFlags.SQLITE_OPEN_SHAREDCACHE;
            var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null);

            if (result != Result.OK)
            {
                throw new SqlException(result, $"Could not open database file: {databasePath} ({result})");
            }

            Contract.ThrowIfNull(handle);

            raw.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds);

            return(new SqlConnection(faultInjector, handle));
        }
Exemplo n.º 14
0
        public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath)
        {
            faultInjector?.OnNewConnection();

            // Use SQLITE_OPEN_NOMUTEX to enable multi-thread mode, where multiple connections can be used provided each
            // one is only used from a single thread at a time.
            // see https://sqlite.org/threadsafe.html for more detail
            var flags  = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE | OpenFlags.SQLITE_OPEN_NOMUTEX;
            var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null);

            if (result != Result.OK)
            {
                throw new SqlException(result, $"Could not open database file: {databasePath} ({result})");
            }

            Contract.ThrowIfNull(handle);

            raw.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds);

            return(new SqlConnection(faultInjector, handle));
        }
Exemplo n.º 15
0
        internal IChecksummedPersistentStorage GetStorage(
            Solution solution, IPersistentStorageFaultInjector faultInjectorOpt = null)
        {
            // For the sake of tests, all solutions are bigger than our threshold, and thus deserve to get storage for them
            var solutionSizeTrackerMock = new Mock <ISolutionSizeTracker>();

            solutionSizeTrackerMock.Setup(m => m.GetSolutionSize(solution.Workspace, solution.Id))
            .Returns(solution.Workspace.Options.GetOption(StorageOptions.SolutionSizeThreshold) + 1);

            // If we handed out one for a previous test, we need to shut that down first
            _persistentLocationService?.RaiseShutdown();
            _persistentLocationService = new MockPersistentStorageLocationService(solution.Id, _persistentFolder);

            var storage = GetStorageService(_persistentLocationService, solutionSizeTrackerMock.Object, faultInjectorOpt).GetStorage(solution, checkBranchId: true);

            // If we're injecting faults, we expect things to be strange
            if (faultInjectorOpt == null)
            {
                Assert.NotEqual(NoOpPersistentStorage.Instance, storage);
            }

            return(storage);
        }
Exemplo n.º 16
0
 internal abstract IChecksummedPersistentStorageService GetStorageService(IPersistentStorageLocationService locationService, ISolutionSizeTracker solutionSizeTracker, IPersistentStorageFaultInjector faultInjector);
 internal abstract AbstractPersistentStorageService GetStorageService(IPersistentStorageLocationService locationService, IPersistentStorageFaultInjector faultInjector);
Exemplo n.º 18
0
 public SQLitePersistentStorageService(IOptionService optionService, IPersistentStorageFaultInjector faultInjector)
     : base(optionService, testing: true)
 {
     _faultInjectorOpt = faultInjector;
 }
Exemplo n.º 19
0
 internal override IPersistentStorageService GetStorageService(IPersistentStorageFaultInjector faultInjector)
 => new EsentPersistentStorageService(_persistentEnabledOptionService, testing: true);
Exemplo n.º 20
0
 private SqlConnection(SafeSqliteHandle handle, IPersistentStorageFaultInjector faultInjector, Dictionary <string, SqlStatement> queryToStatement)
 {
     _handle           = handle;
     _faultInjector    = faultInjector;
     _queryToStatement = queryToStatement;
 }
 internal override AbstractPersistentStorageService GetStorageService(IMefHostExportProvider exportProvider, IPersistentStorageLocationService locationService, IPersistentStorageFaultInjector faultInjector)
 => new SQLitePersistentStorageService(locationService, faultInjector);
Exemplo n.º 22
0
 internal abstract IPersistentStorageService GetStorageService(IPersistentStorageFaultInjector faultInjector);
Exemplo n.º 23
0
 internal override AbstractPersistentStorageService GetStorageService(IPersistentStorageLocationService locationService, ISolutionSizeTracker solutionSizeTracker, IPersistentStorageFaultInjector faultInjector)
 => new SQLitePersistentStorageService(_persistentEnabledOptionService, locationService, solutionSizeTracker, faultInjector);
Exemplo n.º 24
0
 private SqlConnection(IPersistentStorageFaultInjector faultInjector, sqlite3 handle)
 {
     _faultInjector = faultInjector;
     _handle        = handle;
 }
Exemplo n.º 25
0
 internal override AbstractPersistentStorageService GetStorageService(IPersistentStorageLocationService locationService, IPersistentStorageFaultInjector faultInjector)
 => new SQLitePersistentStorageService(locationService, faultInjector);
Exemplo n.º 26
0
 internal override IPersistentStorageService GetStorageService(IPersistentStorageFaultInjector faultInjector)
     => new SQLitePersistentStorageService(_persistentEnabledOptionService, faultInjector);