Beispiel #1
0
        protected override bool TryOpenDatabase(
            Solution solution, string workingFolderPath, string databaseFilePath, out IPersistentStorage storage)
        {
            // try to get db ownership lock. if someone else already has the lock. it will throw
            var dbOwnershipLock = TryGetDatabaseOwnership(databaseFilePath);

            if (dbOwnershipLock == null)
            {
                storage = null;
                return(false);
            }

            SQLitePersistentStorage sqlStorage = null;

            try
            {
                sqlStorage = new SQLitePersistentStorage(
                    workingFolderPath, solution.FilePath, databaseFilePath, dbOwnershipLock, _faultInjectorOpt);

                sqlStorage.Initialize(solution);
            }
            catch (Exception)
            {
                if (sqlStorage != null)
                {
                    // Dispose of the storage, releasing the ownership lock.
                    sqlStorage.Dispose();
                }
                else
                {
                    // The storage was not created so nothing owns the lock.
                    // Dispose the lock to allow reuse.
                    dbOwnershipLock.Dispose();
                }
                throw;
            }

            storage = sqlStorage;
            return(true);
        }
Beispiel #2
0
 public SolutionAccessor(SQLitePersistentStorage storage) : base(storage)
 {
 }
Beispiel #3
0
 public PooledConnection(SQLitePersistentStorage sqlitePersistentStorage, SqlConnection sqlConnection)
 {
     this.sqlitePersistentStorage = sqlitePersistentStorage;
     Connection = sqlConnection;
 }
 public Accessor(SQLitePersistentStorage storage)
 {
     Storage = storage;
     _select_rowid_from_0_where_1          = $@"select rowid from ""{DataTableName}"" where ""{DataIdColumnName}"" = ?";
     _insert_or_replace_into_0_1_2_3_value = $@"insert or replace into ""{DataTableName}""(""{DataIdColumnName}"",""{ChecksumColumnName}"",""{DataColumnName}"") values (?,?,?)";
 }
        /// <summary>
        /// Returns 'true' if the bulk population succeeds, or false if it doesn't.
        /// </summary>
        private bool BulkPopulateProjectIdsWorker(SqlConnection connection, Project project)
        {
            // First, in bulk, get string-ids for all the paths and names for the project and documents.
            if (!AddIndividualProjectAndDocumentComponentIds())
            {
                return(false);
            }

            // Now, ensure we have the project id known locally.  We cannot do this until we've
            // gotten all the IDs for the individual project components as the project ID is built
            // from a compound key using the IDs for the project's FilePath and Name.
            //
            // If this fails for any reason, we can't proceed.
            var projectId = TryGetProjectId(connection, project);

            if (projectId == null)
            {
                return(false);
            }

            // Finally, in bulk, determine the final DB IDs for all our documents. We cannot do
            // this until we have the project-id as the document IDs are built from a compound
            // ID including the project-id.
            return(AddDocumentIds());

            // Local functions below.

            // Use local functions so that other members of this class don't accidentally use these.
            // There are invariants in the context of BulkPopulateProjectIdsWorker that these functions
            // can depend on.
            bool AddIndividualProjectAndDocumentComponentIds()
            {
                var stringsToAdd = new HashSet <string>();

                AddIfUnknownId(project.FilePath, stringsToAdd);
                AddIfUnknownId(project.Name, stringsToAdd);

                foreach (var document in project.Documents)
                {
                    AddIfUnknownId(document.FilePath, stringsToAdd);
                    AddIfUnknownId(document.Name, stringsToAdd);
                }

                return(AddStrings(stringsToAdd));
            }

            bool AddStrings(HashSet <string> stringsToAdd)
            {
                if (stringsToAdd.Count > 0)
                {
                    using var idToString = s_dictionaryPool.GetPooledObject();
                    try
                    {
                        connection.RunInTransaction(
                            state =>
                        {
                            foreach (var value in state.stringsToAdd)
                            {
                                var id = InsertStringIntoDatabase_MustRunInTransaction(state.connection, value);
                                state.idToString.Object.Add(id, value);
                            }
                        },
                            (stringsToAdd, connection, idToString));
                    }
                    catch (SqlException ex) when(ex.Result == Result.CONSTRAINT)
                    {
                        // Constraint exceptions are possible as we may be trying bulk insert
                        // strings while some other thread/process does the same.
                        return(false);
                    }
                    catch (Exception ex)
                    {
                        // Something failed. Log the issue, and let the caller know we should stop
                        // with the bulk population.
                        StorageDatabaseLogger.LogException(ex);
                        return(false);
                    }

                    // We succeeded inserting all the strings.  Ensure our local cache has all the
                    // values we added.
                    foreach (var kvp in idToString.Object)
                    {
                        _stringToIdMap[kvp.Value] = kvp.Key;
                    }
                }

                return(true);
            }

            bool AddDocumentIds()
            {
                var stringsToAdd = new HashSet <string>();

                foreach (var document in project.Documents)
                {
                    // Produce the string like "projId-docPathId-docNameId" so that we can get a
                    // unique ID for it.
                    AddIfUnknownId(GetDocumentIdString(document), stringsToAdd);
                }

                // Ensure we have unique IDs for all these document string ids.  If we fail to
                // bulk import these strings, we can't proceed.
                if (!AddStrings(stringsToAdd))
                {
                    return(false);
                }

                foreach (var document in project.Documents)
                {
                    // Get the integral ID for this document.  It's safe to directly index into
                    // the map as we just successfully added these strings to the DB.
                    var id = _stringToIdMap[GetDocumentIdString(document)];
                    _documentIdToIdMap.TryAdd(document.Id, id);
                }

                return(true);
            }

            string GetDocumentIdString(Document document)
            {
                // We should always be able to index directly into these maps.  This function is only
                // ever called after we called AddIndividualProjectAndDocumentComponentIds.
                var documentPathId = _stringToIdMap[document.FilePath];
                var documentNameId = _stringToIdMap[document.Name];

                var documentIdString = SQLitePersistentStorage.GetDocumentIdString(
                    projectId.Value, documentPathId, documentNameId);

                return(documentIdString);
            }

            void AddIfUnknownId(string value, HashSet <string> stringsToAdd)
            {
                // Null strings are not supported at all.  Just ignore these. Any read/writes
                // to null values will fail and will return 'false/null' to indicate failure
                // (which is part of the documented contract of the persistence layer API).
                if (value == null)
                {
                    return;
                }

                if (!_stringToIdMap.TryGetValue(value, out var id))
                {
                    stringsToAdd.Add(value);
                }
                else
                {
                    // We did know about this string.  However, we want to ensure that the
                    // actual string instance we're pointing to is the one produced by the
                    // rest of the workspace, and not by the database.  This way we don't
                    // end up having tons of duplicate strings in the storage service.
                    //
                    // So overwrite whatever we have so far in the table so we can release
                    // the DB strings.
                    _stringToIdMap[value] = id;
                }
            }
        }
Beispiel #6
0
 public Accessor(SQLitePersistentStorage storage)
 {
     Storage = storage;
 }