The Database module provides a pluggable, domain-scoped key–value storage abstraction for osquery. It is responsible for persisting internal state such as scheduled query results, configuration metadata, event indexes, distributed query state, and performance metrics.
The module exposes a unified interface (IDatabaseInterface) that hides the underlying storage implementation (e.g., RocksDB or in-memory ephemeral storage) and integrates with the osquery plugin registry.
The Database module is designed to:
- Provide a domain-based key–value store abstraction.
- Support pluggable storage backends via the registry system.
- Offer thread-safe access with reset protection.
- Enable batch writes and range operations.
- Support schema versioning and migrations.
- Provide an ephemeral fallback backend for testing or when persistence is disabled.
It is a foundational service used by:
- Scheduled query execution (result storage and epochs)
- Eventing and subscriber state tracking
- Distributed query coordination
- Configuration and persistent settings
- Query performance recording
The Database module follows a plugin-based architecture.
flowchart TD
Client["Core Modules"] -->|"IDatabaseInterface"| OsqueryDB["OsqueryDatabase"]
OsqueryDB -->|"Wrapper Calls"| API["Global Database APIs"]
API -->|"Registry Lookup"| Registry["Plugin Registry"]
Registry -->|"Active Plugin"| Plugin["DatabasePlugin"]
Plugin --> RocksDB["Persistent Backend<br/>rocksdb"]
Plugin --> Ephemeral["Ephemeral Backend<br/>In-Memory"]
-
IDatabaseInterface
Public abstraction used by core components. -
OsqueryDatabase
Concrete implementation delegating to global helper functions. -
Global Database APIs
Functions such asgetDatabaseValue,setDatabaseValue,scanDatabaseKeys, anddeleteDatabaseValue. -
DatabasePlugin (Registry-based)
Abstract plugin defining operations likeget,put,putBatch,remove,removeRange, andscan. -
Concrete Backends
rocksdb(persistent default backend)ephemeral(in-memory fallback backend)
Component: osquery.osquery.database.database.OsqueryDatabase
OsqueryDatabase implements IDatabaseInterface and acts as a thin wrapper over the global database functions.
Responsibilities:
- Forwarding calls to:
getDatabaseValuesetDatabaseValuesetDatabaseBatchdeleteDatabaseValuedeleteDatabaseRangescanDatabaseKeys
- Providing a single static access point via
getOsqueryDatabase().
This ensures consistent database access across the entire codebase.
Component: osquery.osquery.database.ephemeral.EphemeralDatabasePlugin
The Ephemeral backend is an in-memory implementation of DatabasePlugin.
Characteristics:
- Uses nested
std::mapcontainers:
Domain -> (Key -> Value)
- Stores values as
boost::variant<int, std::string>. - Resets state on
setUp(). - Supports:
get(string and int)putputBatchremoveremoveRangescan
Use cases:
- Testing (
initDatabasePluginForTesting()) - When
--disable_databaseis enabled - Fallback when persistent storage fails
The Database module uses domains to separate data categories.
Common domains include:
configurationsquerieseventslogscarvesdistributeddistributed_runningquery_performance
Each domain isolates a logical storage namespace to avoid key collisions and simplify scans.
The module protects database access with:
- A global reader/writer mutex (
kDatabaseReset). - Atomic state flags:
kDBInitializedkDBAllowOpenkDBChecking
flowchart TD
ResetRequest["Reset Request"] --> WriteLock["Acquire Write Lock"]
WriteLock --> TearDown["Plugin tearDown()"]
TearDown --> SetUp["Plugin setUp()"]
SetUp --> Initialized["Mark Initialized"]
Read operations acquire a read lock; reset operations acquire a write lock.
This prevents race conditions during backend reinitialization.
Database initialization occurs via initDatabasePlugin().
flowchart TD
Start["initDatabasePlugin()"] --> CheckFlag{"disable_database?"}
CheckFlag -->|"Yes"| UseEphemeral["Activate Ephemeral Plugin"]
CheckFlag -->|"No"| UseRocksDB["Activate rocksdb Plugin"]
UseEphemeral --> SetActive["Registry setActive()"]
UseRocksDB --> SetActive
SetActive --> RetryLoop["Retry up to 25 times"]
RetryLoop --> Initialized["Set kDBInitialized"]
Features:
- Retry loop to handle persistent lock contention.
- Automatic fallback to ephemeral storage if reset fails.
- Explicit testing initialization via
initDatabasePluginForTesting().
All operations route through the plugin registry.
getDatabaseValue(domain, key, value)
- Validates domain.
- Acquires read lock.
- Delegates to active plugin.
setDatabaseValue(domain, key, value)
- Uses
putBatchinternally. - Supports string and integer overloads.
setDatabaseBatch(domain, data)
- Efficient multi-key write.
- Used for performance-sensitive workflows.
deleteDatabaseValue(domain, key)
deleteDatabaseRange(domain, low, high)
scanDatabaseKeys(domain, keys, prefix, max)
- Supports prefix filtering.
- Supports max key limit.
The Database module supports schema upgrades through:
upgradeDatabase(int to_version)- Version key:
results_version(stored inconfigurationsdomain)
Migration steps are incremental:
- Read current version.
- Execute migration function (e.g.,
migrateV0V1,migrateV1V2). - Persist incremented version.
- Repeat until target version reached.
- JSON format conversion.
- Key renaming for event publishers.
- Removal of legacy suffix-based entries.
This ensures forward compatibility while preserving stored state.
When running as an extension (external registry):
- Direct database access is disabled.
- Requests are forwarded through
Registry::call(). - Extensions cannot implement database plugins.
This enforces centralized control of persistent state.
The --database_dump flag allows printing all domain/key/value pairs.
<domain>[<key>]: <value>
This is useful for debugging state corruption or verifying migration behavior.
If a database reset fails:
- The system switches to the
ephemeralbackend. - A warning is logged.
- Execution continues without persistent storage.
This prioritizes system availability over persistence guarantees.
The Database module underpins several subsystems in the module tree:
- Scheduled queries and performance tracking
- Eventing subscriber persistence
- Distributed query coordination
- Configuration caching
- Logging state management
It is intentionally minimal and focused on storage concerns, delegating domain-specific logic to higher-level modules.
The Database module provides:
- A registry-based pluggable storage abstraction
- Domain-scoped key–value isolation
- Thread-safe operations with reset protection
- Persistent and ephemeral backend support
- Schema migration and versioning
- Extension-aware behavior
It is a core infrastructure component that enables durable state management across the osquery runtime while remaining modular, replaceable, and safe under concurrent access patterns.