/src/duckdb/src/storage/storage_manager.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "duckdb/storage/storage_manager.hpp" |
2 | | #include "duckdb/storage/checkpoint_manager.hpp" |
3 | | #include "duckdb/storage/in_memory_block_manager.hpp" |
4 | | #include "duckdb/storage/single_file_block_manager.hpp" |
5 | | #include "duckdb/storage/object_cache.hpp" |
6 | | |
7 | | #include "duckdb/catalog/catalog.hpp" |
8 | | #include "duckdb/common/file_system.hpp" |
9 | | #include "duckdb/main/database.hpp" |
10 | | #include "duckdb/main/connection.hpp" |
11 | | #include "duckdb/main/client_context.hpp" |
12 | | #include "duckdb/function/function.hpp" |
13 | | #include "duckdb/parser/parsed_data/create_schema_info.hpp" |
14 | | #include "duckdb/transaction/transaction_manager.hpp" |
15 | | #include "duckdb/common/serializer/buffered_file_reader.hpp" |
16 | | |
17 | | namespace duckdb { |
18 | | |
19 | | StorageManager::StorageManager(DatabaseInstance &db, string path, bool read_only) |
20 | 10 | : db(db), path(move(path)), wal(db), read_only(read_only) { |
21 | 10 | } |
22 | | |
23 | 10 | StorageManager::~StorageManager() { |
24 | 10 | } |
25 | | |
26 | 0 | StorageManager &StorageManager::GetStorageManager(ClientContext &context) { |
27 | 0 | return StorageManager::GetStorageManager(*context.db); |
28 | 0 | } |
29 | | |
30 | 44 | BufferManager &BufferManager::GetBufferManager(ClientContext &context) { |
31 | 44 | return BufferManager::GetBufferManager(*context.db); |
32 | 44 | } |
33 | | |
34 | 0 | ObjectCache &ObjectCache::GetObjectCache(ClientContext &context) { |
35 | 0 | return context.db->GetObjectCache(); |
36 | 0 | } |
37 | | |
38 | 0 | bool ObjectCache::ObjectCacheEnabled(ClientContext &context) { |
39 | 0 | return context.db->config.options.object_cache_enable; |
40 | 0 | } |
41 | | |
42 | 60 | bool StorageManager::InMemory() { |
43 | 60 | return path.empty() || path == ":memory:"; |
44 | 60 | } |
45 | | |
46 | 10 | void StorageManager::Initialize() { |
47 | 10 | bool in_memory = InMemory(); |
48 | 10 | if (in_memory && read_only) { |
49 | 0 | throw CatalogException("Cannot launch in-memory database in read-only mode!"); |
50 | 0 | } |
51 | 10 | auto &config = DBConfig::GetConfig(db); |
52 | 10 | auto &catalog = Catalog::GetCatalog(db); |
53 | 10 | buffer_manager = make_unique<BufferManager>(db, config.options.temporary_directory, config.options.maximum_memory); |
54 | | |
55 | | // first initialize the base system catalogs |
56 | | // these are never written to the WAL |
57 | 10 | Connection con(db); |
58 | 10 | con.BeginTransaction(); |
59 | | |
60 | | // create the default schema |
61 | 10 | CreateSchemaInfo info; |
62 | 10 | info.schema = DEFAULT_SCHEMA; |
63 | 10 | info.internal = true; |
64 | 10 | catalog.CreateSchema(*con.context, &info); |
65 | | |
66 | 10 | if (config.options.initialize_default_database) { |
67 | | // initialize default functions |
68 | 10 | BuiltinFunctions builtin(*con.context, catalog); |
69 | 10 | builtin.Initialize(); |
70 | 10 | } |
71 | | |
72 | | // commit transactions |
73 | 10 | con.Commit(); |
74 | | |
75 | 10 | if (!in_memory) { |
76 | | // create or load the database from disk, if not in-memory mode |
77 | 0 | LoadDatabase(); |
78 | 10 | } else { |
79 | 10 | block_manager = make_unique<InMemoryBlockManager>(); |
80 | 10 | } |
81 | 10 | } |
82 | | |
83 | 0 | void StorageManager::LoadDatabase() { |
84 | 0 | string wal_path = path + ".wal"; |
85 | 0 | auto &fs = db.GetFileSystem(); |
86 | 0 | auto &config = db.config; |
87 | 0 | bool truncate_wal = false; |
88 | | // first check if the database exists |
89 | 0 | if (!fs.FileExists(path)) { |
90 | 0 | if (read_only) { |
91 | 0 | throw CatalogException("Cannot open database \"%s\" in read-only mode: database does not exist", path); |
92 | 0 | } |
93 | | // check if the WAL exists |
94 | 0 | if (fs.FileExists(wal_path)) { |
95 | | // WAL file exists but database file does not |
96 | | // remove the WAL |
97 | 0 | fs.RemoveFile(wal_path); |
98 | 0 | } |
99 | | // initialize the block manager while creating a new db file |
100 | 0 | block_manager = make_unique<SingleFileBlockManager>(db, path, read_only, true, config.options.use_direct_io); |
101 | 0 | } else { |
102 | | // initialize the block manager while loading the current db file |
103 | 0 | auto sf_bm = make_unique<SingleFileBlockManager>(db, path, read_only, false, config.options.use_direct_io); |
104 | 0 | auto sf = sf_bm.get(); |
105 | 0 | block_manager = move(sf_bm); |
106 | 0 | sf->LoadFreeList(); |
107 | | |
108 | | //! Load from storage |
109 | 0 | CheckpointManager checkpointer(db); |
110 | 0 | checkpointer.LoadFromStorage(); |
111 | | // check if the WAL file exists |
112 | 0 | if (fs.FileExists(wal_path)) { |
113 | | // replay the WAL |
114 | 0 | truncate_wal = WriteAheadLog::Replay(db, wal_path); |
115 | 0 | } |
116 | 0 | } |
117 | | // initialize the WAL file |
118 | 0 | if (!read_only) { |
119 | 0 | wal.Initialize(wal_path); |
120 | 0 | if (truncate_wal) { |
121 | 0 | wal.Truncate(0); |
122 | 0 | } |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | 0 | void StorageManager::CreateCheckpoint(bool delete_wal, bool force_checkpoint) { |
127 | 0 | if (InMemory() || read_only || !wal.initialized) { |
128 | 0 | return; |
129 | 0 | } |
130 | 0 | if (wal.GetWALSize() > 0 || db.config.options.force_checkpoint || force_checkpoint) { |
131 | | // we only need to checkpoint if there is anything in the WAL |
132 | 0 | CheckpointManager checkpointer(db); |
133 | 0 | checkpointer.CreateCheckpoint(); |
134 | 0 | } |
135 | 0 | if (delete_wal) { |
136 | 0 | wal.Delete(); |
137 | 0 | } |
138 | 0 | } |
139 | | |
140 | | } // namespace duckdb |