원클릭으로
subsystem-summary-of-database
read this skill for a token-efficient summary of the database subsystem
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
read this skill for a token-efficient summary of the database subsystem
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | subsystem-summary-of-database |
| description | read this skill for a token-efficient summary of the database subsystem |
The database subsystem provides the persistence layer for stellar-core, wrapping the SOCI C++ database-access library to manage connections to SQLite or PostgreSQL backends. It handles schema versioning/migration, connection pooling for worker threads, metrics collection, and a dual-database architecture (main + misc) for SQLite to avoid write-lock contention.
Database class; connection management, schema migration, pooling, metrics.Database (inherits NonMovableOrCopyable)The central class that owns all database connections for an Application instance. One Database exists per application.
Members:
mApp (Application&) — Back-reference to the owning application.mQueryMeter (medida::Meter&) — Metrics meter counting all SQL query executions.mSession (SessionWrapper, name="main") — Primary SOCI session for ledger state; used for all writes on the main DB.mMiscSession (SessionWrapper, name="misc") — Secondary SOCI session for miscellaneous/consensus data (SQLite only).mPool / mMiscPool (unique_ptr<soci::connection_pool>) — Lazily-created connection pools for worker-thread read access.gDriversRegistered (static bool) — Ensures SOCI backend drivers (sqlite3, postgresql) are registered exactly once.SessionWrapper (inherits NonCopyable)A thin RAII wrapper around soci::session that carries a human-readable session name (e.g., "main" or "misc"). Two constructors: one for standalone sessions, one that borrows from a connection_pool.
StatementContext (inherits NonCopyable)RAII handle for borrowing a SOCI prepared statement. On construction it calls clean_up(false) to unbind any prior data; on destruction it does the same cleanup. Returned by Database::getPreparedStatement(). Supports move semantics.
DatabaseTypeSpecificOperation<T> (template, abstract)A visitor/strategy pattern that allows callers to write code specific to the database backend without switching on backend type everywhere. Has two pure virtual methods:
doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) — SQLite path.doPostgresSpecificOperation(soci::postgresql_session_backend* pg) — PostgreSQL path (conditionally compiled under USE_POSTGRES).Used via Database::doDatabaseTypeSpecificOperation() or the free-function overload that takes a raw soci::session&.
DatabaseConfigureSessionOp (local to Database.cpp)A concrete DatabaseTypeSpecificOperation<void> used internally during connection setup. Performs:
carray() extension.Two independent schema version tracks are maintained:
MIN_SCHEMA_VERSION = 25, SCHEMA_VERSION = 26.PersistentState::kDatabaseSchema in the storestate table.applySchemaUpgrade(vers) applies incremental migrations in a SOCI transaction:
publishqueue table; drops misc tables from main DB if misc DB is active.dbbackend entry from storestate.MIN_MISC_SCHEMA_VERSION = 0, MISC_SCHEMA_VERSION = 1.PersistentState::kMiscDatabaseSchema in the misc DB's own storestate.applyMiscSchemaUpgrade(vers) applies incremental migrations:
populateMiscDatabase().upgradeToCurrentSchema())doMigration().doMigration().doMigration() validates version bounds, then loops applying upgrades one version at a time, persisting the new version after each step.SQLite locks the entire database file during writes, blocking parallelism between ledger apply and consensus/overlay operations. To mitigate this, the subsystem splits data across two SQLite files:
peers, ban, quoruminfo, scpquorums, scphistory, slotstate (defined in kMiscTables).Applicability: Only for on-disk SQLite (canUseMiscDB() returns true when canUsePool() && isSqlite()). PostgreSQL handles concurrent writes natively, so it uses a single database with mMiscSession falling back to mSession.
Misc DB naming: getMiscDBName() inserts "-misc" before the file extension of the main DB path (e.g., stellar.db → stellar-misc.db).
Data migration (populateMiscDatabase()):
source_db in the misc session.kMiscTables, copies all rows via INSERT INTO ... SELECT * FROM source_db.<table>.source_db after transaction commit to avoid lock contention.Pools are lazily created on first call to getPool() or getMiscPool().
Pool size: std::thread::hardware_concurrency() entries. If misc DB is active, each pool gets half (min 1).
Pool creation (createPool()):
soci::connection_pool of size n.DatabaseConfigureSessionOp.Access constraints:
getSession() and getMiscSession() assert threadIsMain() — direct session access is restricted to the main thread.getPool() / getMiscPool()).Database Public API| Function | Purpose |
|---|---|
Database(Application&) | Constructor: registers drivers, logs connection string (password-redacted), calls open(). |
open() | Opens main session, configures it; opens misc session if canUseMiscDB(). |
initialize() | Drops and recreates all tables (used by new-db command). For SQLite, deletes DB files first. Creates overlay, persistent state, ledger header, herder persistence, ban tables. |
upgradeToCurrentSchema() | Runs schema migrations for both misc and main DBs. |
getPreparedStatement(query, session) | Allocates and prepares a SOCI statement, returns it wrapped in StatementContext. |
getInsertTimer/getSelectTimer/getDeleteTimer/getUpdateTimer/getUpsertTimer(entityName) | Returns a medida::TimerContext for timing and counting SQL operations, grouped by entity name. |
setCurrentTransactionReadOnly() | On PostgreSQL, issues SET TRANSACTION READ ONLY. No-op on SQLite. |
isSqlite() | Returns true if connection string contains "sqlite3://". |
canUseMiscDB() | True for on-disk SQLite only. |
canUsePool() | True unless using in-memory SQLite (sqlite3://:memory:). |
getSimpleCollationClause() | Returns COLLATE "C" for PostgreSQL (byte-value comparison), empty for SQLite. |
getSession() / getMiscSession() | Returns main/misc SessionWrapper; asserts main thread. getMiscSession() falls back to main session if misc DB unavailable. |
getRawSession() / getRawMiscSession() | Convenience accessors returning soci::session&. |
getPool() / getMiscPool() | Returns (lazily-created) connection pools for worker threads. |
getMainDBSchemaVersion() / getMiscDBSchemaVersion() | Reads schema version from persistent state. |
doDatabaseTypeSpecificOperation(session, op) | Dispatches to the correct backend-specific method on op via dynamic_cast on the SOCI backend. |
| Function | Purpose |
|---|---|
doDatabaseTypeSpecificOperation<T>(soci::session&, op) | Non-member overload operating on raw soci::session. |
decodeOpaqueXDR<T>(string, out) | Base64-decodes a string then XDR-deserializes into out. |
decodeOpaqueXDR<T>(string, indicator, out) | Same but handles null indicators (sets out = T{} if null). |
removePasswordFromConnectionString(string) | Regex-replaces password values with ******** in connection strings for safe logging. |
dropMiscTablesFromMain(Application&) | Drops all kMiscTables from the main DB (called during v26 migration). |
validateVersion(vers, min, max) | Throws if schema version is outside supported range. |
DatabaseUtils Namespace| Function | Purpose |
|---|---|
deleteOldEntriesHelper(sess, ledgerSeq, count, tableName, ledgerSeqColumn) | Batch-deletes old rows: finds MIN of the ledger-seq column, deletes rows up to min(curMin + count, ledgerSeq). Used for pruning historical data from various tables. |
Application
└── Database (1:1, owned by Application)
├── mSession (SessionWrapper, "main") — primary DB session
│ └── soci::session — actual SOCI connection
├── mMiscSession (SessionWrapper, "misc") — secondary DB session (SQLite only)
│ └── soci::session — actual SOCI connection
├── mPool (unique_ptr<soci::connection_pool>) — lazily created, for main DB
│ └── N × soci::session (one per hardware thread)
└── mMiscPool (unique_ptr<soci::connection_pool>) — lazily created, for misc DB
└── N/2 × soci::session
StatementContext objects are transient: created by getPreparedStatement(), hold a shared_ptr<soci::statement>, cleaned up when they go out of scope.
Application constructs Database, which registers SOCI drivers and opens connections.open() configures each session (SQLite pragmas or PostgreSQL isolation level).new-db: initialize() drops/recreates all tables, sets schema version to MIN_SCHEMA_VERSION.upgradeToCurrentSchema() reads current versions and applies incremental migrations.getInsertTimer("entity") etc. — starts timing.getSession() or getMiscSession().session << "SQL...") or obtains a prepared statement via getPreparedStatement(query, session).StatementContext RAII ensures cleanup.getPool() or getMiscPool() to get a soci::connection_pool.SessionWrapper from the pool (SOCI automatically checks out/returns connections).upgradeToCurrentSchema() is called during startup.DatabaseUtils::deleteOldEntriesHelper() with a target ledger sequence, batch count, table name, and column name.| Constant | Value | Purpose |
|---|---|---|
MIN_SCHEMA_VERSION | 25 | Oldest main DB schema this binary can open |
SCHEMA_VERSION | 26 | Current target main DB schema |
FIRST_MAIN_VERSION_WITH_MISC | 26 | Main schema version at which misc DB was introduced |
MIN_MISC_SCHEMA_VERSION | 0 | Oldest misc DB schema (0 = no misc table yet) |
MISC_SCHEMA_VERSION | 1 | Current target misc DB schema |
MIN_SQLITE_VERSION | 3.45 | Minimum SQLite version (compiled check) |
MIN_POSTGRESQL_VERSION | 9.5 | Minimum PostgreSQL version |
mSession and mMiscSession. All write operations go through these. Access is guarded by releaseAssert(threadIsMain()).mPool, mMiscPool). Each pool entry is an independently configured SOCI session.extending yourself with a new reusable skill by interviewing the user
analyzing a change to determine what tests are needed and adding them to the test suite
modifying build configuration to enable/disable variants, switch compilers or flags, or otherwise prepare for a build
reviewing a change for semantic correctness, simplicity, design consistency, and completeness
reviewing a git diff for small localized coding mistakes that can be fixed without high-level understanding
how to run make correctly to get a good build, and otherwise understand the build system