File: Storage\SQLite\v2\Database.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.SQLite.v2;
 
internal enum Database
{
    /// <summary>
    /// The database that is stored on disk and actually persists data across VS sessions.
    /// </summary>
    Main,
 
    /// <summary>
    /// An in-memory database that caches values before being transferred to <see
    /// cref="Main"/>.  Does not persist across VS sessions.
    /// </summary>
    WriteCache,
}
 
internal static class DatabaseExtensions
{
    /// <summary>
    /// Name of the different dbs.
    /// 
    /// 1. "main" is the default that sqlite uses.  This just allows us to be explicit that we
    /// want this db.
    ///
    /// 2. "writecache" is the name for the in-memory write-cache db.  Writes will be staged
    /// there and will be periodically flushed to the real on-disk db to help with perf.
    ///
    /// Perf measurements show this as significantly better than all other design options. It's
    /// also one of the simplest in terms of the design.
    ///
    /// The design options in order of performance (slowest to fastest) are:
    ///
    /// 1. send writes directly to the main db. this is incredibly slow (since each write incurs
    /// the full IO overhead of a transaction). It is the absolute simplest in terms of
    /// implementation though.
    ///
    /// 2. send writes to a temporary on-disk db (with synchronous=off and journal_mode=memory),
    /// then flush those to the main db.  This is also quite slow due to their still needing to
    /// be disk IO with each write.  Implementation is fairly simple, with writes just going to
    /// the temp db and reads going to both.
    ///
    /// 3. Buffer writes in (.net) memory and flush them to disk.  This is much faster than '1'
    /// or '2' but requires a lot of manual book-keeping and extra complexity. For example, any
    /// reads go to the db.  So that means that reads have to ensure that any writes to the same
    /// rows have been persisted so they can observe them.
    ///
    /// 4. send writes to an sqlite in-memory cache DB.  This is extremely fast for sqlite as
    /// there is no actual IO that is performed.  It is also easy in terms of bookkeeping as
    /// both DBs have the same schema and are easy to move data between. '4' is faster than all
    /// of the above. Complexity is minimized as reading can be done just by examining both DBs
    /// in the same way. It's not as simple as '1' but it's much simpler than '3'.
    /// </summary>
    public static string GetName(this Database database)
        => database switch
        {
            Database.Main => "main",
            Database.WriteCache => "writecache",
            _ => throw ExceptionUtilities.UnexpectedValue(database),
        };
}