duckdb 0.7.2-dev1803.0 → 0.7.2-dev1898.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/duckdb/src/catalog/catalog.cpp +27 -27
- package/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp +6 -6
- package/src/duckdb/src/catalog/catalog_set.cpp +27 -25
- package/src/duckdb/src/catalog/default/default_functions.cpp +6 -6
- package/src/duckdb/src/catalog/default/default_types.cpp +4 -4
- package/src/duckdb/src/catalog/default/default_views.cpp +4 -4
- package/src/duckdb/src/catalog/dependency_list.cpp +7 -6
- package/src/duckdb/src/catalog/dependency_manager.cpp +44 -38
- package/src/duckdb/src/common/serializer/buffered_file_reader.cpp +11 -6
- package/src/duckdb/src/common/sort/sorted_block.cpp +9 -4
- package/src/duckdb/src/common/types/batched_data_collection.cpp +2 -1
- package/src/duckdb/src/common/types/column_data_allocator.cpp +1 -0
- package/src/duckdb/src/common/types/vector.cpp +2 -2
- package/src/duckdb/src/common/vector_operations/vector_copy.cpp +14 -11
- package/src/duckdb/src/execution/operator/aggregate/distinct_aggregate_data.cpp +1 -1
- package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +51 -50
- package/src/duckdb/src/execution/operator/join/physical_iejoin.cpp +4 -0
- package/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +14 -13
- package/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +20 -20
- package/src/duckdb/src/execution/operator/schema/physical_create_table.cpp +2 -2
- package/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +1 -1
- package/src/duckdb/src/execution/physical_plan/plan_create_table.cpp +3 -3
- package/src/duckdb/src/execution/physical_plan/plan_delete.cpp +1 -1
- package/src/duckdb/src/execution/physical_plan/plan_insert.cpp +1 -1
- package/src/duckdb/src/execution/physical_plan/plan_update.cpp +1 -1
- package/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +172 -63
- package/src/duckdb/src/function/cast/cast_function_set.cpp +2 -1
- package/src/duckdb/src/function/scalar/operators/arithmetic.cpp +15 -9
- package/src/duckdb/src/function/scalar/sequence/nextval.cpp +29 -29
- package/src/duckdb/src/function/scalar/string/damerau_levenshtein.cpp +106 -0
- package/src/duckdb/src/function/scalar/string/regexp.cpp +145 -28
- package/src/duckdb/src/function/scalar/string_functions.cpp +1 -0
- package/src/duckdb/src/function/table/checkpoint.cpp +4 -4
- package/src/duckdb/src/function/table/system/duckdb_columns.cpp +24 -24
- package/src/duckdb/src/function/table/system/duckdb_constraints.cpp +7 -6
- package/src/duckdb/src/function/table/system/duckdb_databases.cpp +1 -1
- package/src/duckdb/src/function/table/system/duckdb_dependencies.cpp +11 -11
- package/src/duckdb/src/function/table/system/pragma_database_size.cpp +1 -1
- package/src/duckdb/src/function/table/system/pragma_table_info.cpp +17 -18
- package/src/duckdb/src/function/table/table_scan.cpp +8 -11
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +9 -9
- package/src/duckdb/src/include/duckdb/catalog/catalog_entry_map.hpp +38 -0
- package/src/duckdb/src/include/duckdb/catalog/catalog_transaction.hpp +4 -3
- package/src/duckdb/src/include/duckdb/catalog/default/default_functions.hpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/default/default_types.hpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/default/default_views.hpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/dependency.hpp +4 -5
- package/src/duckdb/src/include/duckdb/catalog/dependency_list.hpp +4 -5
- package/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp +10 -9
- package/src/duckdb/src/include/duckdb/common/allocator.hpp +2 -1
- package/src/duckdb/src/include/duckdb/common/field_writer.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/helper.hpp +9 -0
- package/src/duckdb/src/include/duckdb/common/optional_ptr.hpp +29 -6
- package/src/duckdb/src/include/duckdb/common/serializer/buffered_file_reader.hpp +6 -5
- package/src/duckdb/src/include/duckdb/common/serializer.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/types/row_data_collection.hpp +1 -0
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_insert.hpp +5 -5
- package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_table.hpp +2 -2
- package/src/duckdb/src/include/duckdb/function/cast/default_casts.hpp +3 -2
- package/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp +4 -0
- package/src/duckdb/src/include/duckdb/main/client_config.hpp +5 -0
- package/src/duckdb/src/include/duckdb/main/database_manager.hpp +4 -3
- package/src/duckdb/src/include/duckdb/main/query_result.hpp +3 -2
- package/src/duckdb/src/include/duckdb/main/settings.hpp +19 -0
- package/src/duckdb/src/include/duckdb/optimizer/filter_combiner.hpp +7 -7
- package/src/duckdb/src/include/duckdb/optimizer/matcher/expression_matcher.hpp +11 -11
- package/src/duckdb/src/include/duckdb/optimizer/matcher/set_matcher.hpp +8 -8
- package/src/duckdb/src/include/duckdb/optimizer/rule/arithmetic_simplification.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/case_simplification.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/comparison_simplification.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/conjunction_simplification.hpp +2 -2
- package/src/duckdb/src/include/duckdb/optimizer/rule/constant_folding.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/date_part_simplification.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/distributivity.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/empty_needle_removal.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/enum_comparison.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/equal_or_null_simplification.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/in_clause_simplification.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/like_optimizations.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/move_constants.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/ordered_aggregate_optimizer.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule/regex_optimizations.hpp +1 -1
- package/src/duckdb/src/include/duckdb/optimizer/rule.hpp +2 -2
- package/src/duckdb/src/include/duckdb/parser/base_expression.hpp +1 -1
- package/src/duckdb/src/include/duckdb/parser/expression_map.hpp +19 -6
- package/src/duckdb/src/include/duckdb/parser/expression_util.hpp +1 -1
- package/src/duckdb/src/include/duckdb/parser/parser.hpp +1 -7
- package/src/duckdb/src/include/duckdb/parser/parser_options.hpp +23 -0
- package/src/duckdb/src/include/duckdb/parser/transformer.hpp +5 -3
- package/src/duckdb/src/include/duckdb/planner/expression.hpp +5 -2
- package/src/duckdb/src/include/duckdb/planner/expression_binder/base_select_binder.hpp +1 -1
- package/src/duckdb/src/include/duckdb/planner/expression_binder/order_binder.hpp +3 -3
- package/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +10 -2
- package/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp +1 -0
- package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +49 -126
- package/src/duckdb/src/include/duckdb/storage/meta_block_reader.hpp +5 -5
- package/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +159 -0
- package/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp +1 -0
- package/src/duckdb/src/include/duckdb/transaction/meta_transaction.hpp +6 -5
- package/src/duckdb/src/main/client_context.cpp +5 -3
- package/src/duckdb/src/main/config.cpp +2 -0
- package/src/duckdb/src/main/database.cpp +2 -1
- package/src/duckdb/src/main/database_manager.cpp +4 -4
- package/src/duckdb/src/main/settings/settings.cpp +36 -0
- package/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp +2 -2
- package/src/duckdb/src/optimizer/cse_optimizer.cpp +4 -4
- package/src/duckdb/src/optimizer/deliminator.cpp +13 -11
- package/src/duckdb/src/optimizer/expression_rewriter.cpp +2 -2
- package/src/duckdb/src/optimizer/filter_combiner.cpp +67 -65
- package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +1 -0
- package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +26 -25
- package/src/duckdb/src/optimizer/matcher/expression_matcher.cpp +23 -21
- package/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp +7 -6
- package/src/duckdb/src/optimizer/rule/case_simplification.cpp +2 -2
- package/src/duckdb/src/optimizer/rule/comparison_simplification.cpp +6 -7
- package/src/duckdb/src/optimizer/rule/conjunction_simplification.cpp +9 -8
- package/src/duckdb/src/optimizer/rule/constant_folding.cpp +7 -7
- package/src/duckdb/src/optimizer/rule/date_part_simplification.cpp +3 -3
- package/src/duckdb/src/optimizer/rule/distributivity.cpp +5 -5
- package/src/duckdb/src/optimizer/rule/empty_needle_removal.cpp +6 -6
- package/src/duckdb/src/optimizer/rule/enum_comparison.cpp +4 -4
- package/src/duckdb/src/optimizer/rule/equal_or_null_simplification.cpp +23 -26
- package/src/duckdb/src/optimizer/rule/in_clause_simplification_rule.cpp +2 -3
- package/src/duckdb/src/optimizer/rule/like_optimizations.cpp +3 -3
- package/src/duckdb/src/optimizer/rule/move_constants.cpp +6 -6
- package/src/duckdb/src/optimizer/rule/ordered_aggregate_optimizer.cpp +2 -2
- package/src/duckdb/src/optimizer/rule/regex_optimizations.cpp +3 -3
- package/src/duckdb/src/parser/expression_util.cpp +6 -6
- package/src/duckdb/src/parser/parser.cpp +1 -1
- package/src/duckdb/src/parser/transform/expression/transform_operator.cpp +7 -3
- package/src/duckdb/src/parser/transform/helpers/transform_groupby.cpp +3 -3
- package/src/duckdb/src/parser/transformer.cpp +6 -5
- package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +2 -2
- package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +3 -3
- package/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp +5 -5
- package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +2 -2
- package/src/duckdb/src/planner/expression_binder/base_select_binder.cpp +4 -4
- package/src/duckdb/src/planner/expression_binder/order_binder.cpp +3 -3
- package/src/duckdb/src/storage/buffer/block_handle.cpp +3 -2
- package/src/duckdb/src/storage/buffer/block_manager.cpp +3 -1
- package/src/duckdb/src/storage/buffer/buffer_handle.cpp +1 -0
- package/src/duckdb/src/storage/buffer/buffer_pool_reservation.cpp +3 -0
- package/src/duckdb/src/storage/buffer_manager.cpp +35 -726
- package/src/duckdb/src/storage/checkpoint_manager.cpp +2 -2
- package/src/duckdb/src/storage/meta_block_reader.cpp +6 -5
- package/src/duckdb/src/storage/standard_buffer_manager.cpp +801 -0
- package/src/duckdb/src/storage/wal_replay.cpp +2 -2
- package/src/duckdb/src/transaction/meta_transaction.cpp +13 -13
- package/src/duckdb/src/transaction/transaction.cpp +1 -1
- package/src/duckdb/src/transaction/transaction_context.cpp +1 -1
- package/src/duckdb/third_party/libpg_query/include/parser/gram.hpp +949 -947
- package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +16431 -16385
- package/src/duckdb/third_party/libpg_query/src_backend_parser_scan.cpp +503 -493
- package/src/duckdb/ub_src_function_scalar_string.cpp +2 -0
- package/src/duckdb/ub_src_storage.cpp +2 -0
@@ -0,0 +1,801 @@
|
|
1
|
+
#include "duckdb/storage/standard_buffer_manager.hpp"
|
2
|
+
|
3
|
+
#include "duckdb/common/allocator.hpp"
|
4
|
+
#include "duckdb/common/exception.hpp"
|
5
|
+
#include "duckdb/common/set.hpp"
|
6
|
+
#include "duckdb/storage/in_memory_block_manager.hpp"
|
7
|
+
#include "duckdb/storage/storage_manager.hpp"
|
8
|
+
#include "duckdb/main/attached_database.hpp"
|
9
|
+
#include "duckdb/main/database.hpp"
|
10
|
+
#include "duckdb/storage/buffer/buffer_pool.hpp"
|
11
|
+
|
12
|
+
namespace duckdb {
|
13
|
+
|
14
|
+
struct BufferAllocatorData : PrivateAllocatorData {
|
15
|
+
explicit BufferAllocatorData(StandardBufferManager &manager) : manager(manager) {
|
16
|
+
}
|
17
|
+
|
18
|
+
StandardBufferManager &manager;
|
19
|
+
};
|
20
|
+
|
21
|
+
unique_ptr<FileBuffer> StandardBufferManager::ConstructManagedBuffer(idx_t size, unique_ptr<FileBuffer> &&source,
|
22
|
+
FileBufferType type) {
|
23
|
+
if (source) {
|
24
|
+
auto tmp = std::move(source);
|
25
|
+
D_ASSERT(tmp->AllocSize() == BufferManager::GetAllocSize(size));
|
26
|
+
return make_uniq<FileBuffer>(*tmp, type);
|
27
|
+
} else {
|
28
|
+
// no re-usable buffer: allocate a new buffer
|
29
|
+
return make_uniq<FileBuffer>(Allocator::Get(db), type, size);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
class TemporaryFileManager;
|
34
|
+
|
35
|
+
class TemporaryDirectoryHandle {
|
36
|
+
public:
|
37
|
+
TemporaryDirectoryHandle(DatabaseInstance &db, string path_p);
|
38
|
+
~TemporaryDirectoryHandle();
|
39
|
+
|
40
|
+
TemporaryFileManager &GetTempFile();
|
41
|
+
|
42
|
+
private:
|
43
|
+
DatabaseInstance &db;
|
44
|
+
string temp_directory;
|
45
|
+
bool created_directory = false;
|
46
|
+
unique_ptr<TemporaryFileManager> temp_file;
|
47
|
+
};
|
48
|
+
|
49
|
+
void StandardBufferManager::SetTemporaryDirectory(const string &new_dir) {
|
50
|
+
if (temp_directory_handle) {
|
51
|
+
throw NotImplementedException("Cannot switch temporary directory after the current one has been used");
|
52
|
+
}
|
53
|
+
this->temp_directory = new_dir;
|
54
|
+
}
|
55
|
+
|
56
|
+
StandardBufferManager::StandardBufferManager(DatabaseInstance &db, string tmp)
|
57
|
+
: BufferManager(), db(db), buffer_pool(db.GetBufferPool()), temp_directory(std::move(tmp)),
|
58
|
+
temporary_id(MAXIMUM_BLOCK), buffer_allocator(BufferAllocatorAllocate, BufferAllocatorFree,
|
59
|
+
BufferAllocatorRealloc, make_uniq<BufferAllocatorData>(*this)) {
|
60
|
+
temp_block_manager = make_uniq<InMemoryBlockManager>(*this);
|
61
|
+
}
|
62
|
+
|
63
|
+
StandardBufferManager::~StandardBufferManager() {
|
64
|
+
}
|
65
|
+
|
66
|
+
BufferPool &StandardBufferManager::GetBufferPool() {
|
67
|
+
return buffer_pool;
|
68
|
+
}
|
69
|
+
|
70
|
+
idx_t StandardBufferManager::GetUsedMemory() const {
|
71
|
+
return buffer_pool.GetUsedMemory();
|
72
|
+
}
|
73
|
+
idx_t StandardBufferManager::GetMaxMemory() const {
|
74
|
+
return buffer_pool.GetMaxMemory();
|
75
|
+
}
|
76
|
+
|
77
|
+
// POTENTIALLY PROBLEMATIC
|
78
|
+
// void StandardBufferManager::IncreaseUsedMemory(idx_t size, bool unsafe) {
|
79
|
+
// if (!unsafe && buffer_pool.GetUsedMemory() + size > buffer_pool.GetMaxMemory()) {
|
80
|
+
// throw OutOfMemoryException("Failed to allocate data of size %lld%s", size, InMemoryWarning());
|
81
|
+
// }
|
82
|
+
// buffer_pool.IncreaseUsedMemory(size);
|
83
|
+
//}
|
84
|
+
|
85
|
+
template <typename... ARGS>
|
86
|
+
TempBufferPoolReservation StandardBufferManager::EvictBlocksOrThrow(idx_t memory_delta, unique_ptr<FileBuffer> *buffer,
|
87
|
+
ARGS... args) {
|
88
|
+
auto r = buffer_pool.EvictBlocks(memory_delta, buffer_pool.maximum_memory, buffer);
|
89
|
+
if (!r.success) {
|
90
|
+
throw OutOfMemoryException(args..., InMemoryWarning());
|
91
|
+
}
|
92
|
+
return std::move(r.reservation);
|
93
|
+
}
|
94
|
+
|
95
|
+
shared_ptr<BlockHandle> StandardBufferManager::RegisterSmallMemory(idx_t block_size) {
|
96
|
+
D_ASSERT(block_size < Storage::BLOCK_SIZE);
|
97
|
+
auto res = EvictBlocksOrThrow(block_size, nullptr, "could not allocate block of %lld bytes (%lld/%lld used) %s",
|
98
|
+
block_size, GetUsedMemory(), GetMaxMemory());
|
99
|
+
|
100
|
+
auto buffer = ConstructManagedBuffer(block_size, nullptr, FileBufferType::TINY_BUFFER);
|
101
|
+
|
102
|
+
// create a new block pointer for this block
|
103
|
+
return make_shared<BlockHandle>(*temp_block_manager, ++temporary_id, std::move(buffer), false, block_size,
|
104
|
+
std::move(res));
|
105
|
+
}
|
106
|
+
|
107
|
+
shared_ptr<BlockHandle> StandardBufferManager::RegisterMemory(idx_t block_size, bool can_destroy) {
|
108
|
+
D_ASSERT(block_size >= Storage::BLOCK_SIZE);
|
109
|
+
auto alloc_size = GetAllocSize(block_size);
|
110
|
+
// first evict blocks until we have enough memory to store this buffer
|
111
|
+
unique_ptr<FileBuffer> reusable_buffer;
|
112
|
+
auto res =
|
113
|
+
EvictBlocksOrThrow(alloc_size, &reusable_buffer, "could not allocate block of %lld bytes (%lld/%lld used) %s",
|
114
|
+
alloc_size, GetUsedMemory(), GetMaxMemory());
|
115
|
+
|
116
|
+
auto buffer = ConstructManagedBuffer(block_size, std::move(reusable_buffer));
|
117
|
+
|
118
|
+
// create a new block pointer for this block
|
119
|
+
return make_shared<BlockHandle>(*temp_block_manager, ++temporary_id, std::move(buffer), can_destroy, alloc_size,
|
120
|
+
std::move(res));
|
121
|
+
}
|
122
|
+
|
123
|
+
BufferHandle StandardBufferManager::Allocate(idx_t block_size, bool can_destroy, shared_ptr<BlockHandle> *block) {
|
124
|
+
shared_ptr<BlockHandle> local_block;
|
125
|
+
auto block_ptr = block ? block : &local_block;
|
126
|
+
*block_ptr = RegisterMemory(block_size, can_destroy);
|
127
|
+
return Pin(*block_ptr);
|
128
|
+
}
|
129
|
+
|
130
|
+
void StandardBufferManager::ReAllocate(shared_ptr<BlockHandle> &handle, idx_t block_size) {
|
131
|
+
D_ASSERT(block_size >= Storage::BLOCK_SIZE);
|
132
|
+
lock_guard<mutex> lock(handle->lock);
|
133
|
+
D_ASSERT(handle->state == BlockState::BLOCK_LOADED);
|
134
|
+
D_ASSERT(handle->memory_usage == handle->buffer->AllocSize());
|
135
|
+
D_ASSERT(handle->memory_usage == handle->memory_charge.size);
|
136
|
+
|
137
|
+
auto req = handle->buffer->CalculateMemory(block_size);
|
138
|
+
int64_t memory_delta = (int64_t)req.alloc_size - handle->memory_usage;
|
139
|
+
|
140
|
+
if (memory_delta == 0) {
|
141
|
+
return;
|
142
|
+
} else if (memory_delta > 0) {
|
143
|
+
// evict blocks until we have space to resize this block
|
144
|
+
auto reservation = EvictBlocksOrThrow(memory_delta, nullptr, "failed to resize block from %lld to %lld%s",
|
145
|
+
handle->memory_usage, req.alloc_size);
|
146
|
+
// EvictBlocks decrements 'current_memory' for us.
|
147
|
+
handle->memory_charge.Merge(std::move(reservation));
|
148
|
+
} else {
|
149
|
+
// no need to evict blocks, but we do need to decrement 'current_memory'.
|
150
|
+
handle->memory_charge.Resize(req.alloc_size);
|
151
|
+
}
|
152
|
+
|
153
|
+
handle->ResizeBuffer(block_size, memory_delta);
|
154
|
+
}
|
155
|
+
|
156
|
+
BufferHandle StandardBufferManager::Pin(shared_ptr<BlockHandle> &handle) {
|
157
|
+
idx_t required_memory;
|
158
|
+
{
|
159
|
+
// lock the block
|
160
|
+
lock_guard<mutex> lock(handle->lock);
|
161
|
+
// check if the block is already loaded
|
162
|
+
if (handle->state == BlockState::BLOCK_LOADED) {
|
163
|
+
// the block is loaded, increment the reader count and return a pointer to the handle
|
164
|
+
handle->readers++;
|
165
|
+
return handle->Load(handle);
|
166
|
+
}
|
167
|
+
required_memory = handle->memory_usage;
|
168
|
+
}
|
169
|
+
// evict blocks until we have space for the current block
|
170
|
+
unique_ptr<FileBuffer> reusable_buffer;
|
171
|
+
auto reservation =
|
172
|
+
EvictBlocksOrThrow(required_memory, &reusable_buffer, "failed to pin block of size %lld%s", required_memory);
|
173
|
+
// lock the handle again and repeat the check (in case anybody loaded in the mean time)
|
174
|
+
lock_guard<mutex> lock(handle->lock);
|
175
|
+
// check if the block is already loaded
|
176
|
+
if (handle->state == BlockState::BLOCK_LOADED) {
|
177
|
+
// the block is loaded, increment the reader count and return a pointer to the handle
|
178
|
+
handle->readers++;
|
179
|
+
reservation.Resize(0);
|
180
|
+
return handle->Load(handle);
|
181
|
+
}
|
182
|
+
// now we can actually load the current block
|
183
|
+
D_ASSERT(handle->readers == 0);
|
184
|
+
handle->readers = 1;
|
185
|
+
auto buf = handle->Load(handle, std::move(reusable_buffer));
|
186
|
+
handle->memory_charge = std::move(reservation);
|
187
|
+
// In the case of a variable sized block, the buffer may be smaller than a full block.
|
188
|
+
int64_t delta = handle->buffer->AllocSize() - handle->memory_usage;
|
189
|
+
if (delta) {
|
190
|
+
D_ASSERT(delta < 0);
|
191
|
+
handle->memory_usage += delta;
|
192
|
+
handle->memory_charge.Resize(handle->memory_usage);
|
193
|
+
}
|
194
|
+
D_ASSERT(handle->memory_usage == handle->buffer->AllocSize());
|
195
|
+
return buf;
|
196
|
+
}
|
197
|
+
|
198
|
+
void StandardBufferManager::PurgeQueue() {
|
199
|
+
buffer_pool.PurgeQueue();
|
200
|
+
}
|
201
|
+
|
202
|
+
void StandardBufferManager::AddToEvictionQueue(shared_ptr<BlockHandle> &handle) {
|
203
|
+
buffer_pool.AddToEvictionQueue(handle);
|
204
|
+
}
|
205
|
+
|
206
|
+
void StandardBufferManager::VerifyZeroReaders(shared_ptr<BlockHandle> &handle) {
|
207
|
+
#ifdef DUCKDB_DEBUG_DESTROY_BLOCKS
|
208
|
+
auto replacement_buffer = make_uniq<FileBuffer>(Allocator::Get(db), handle->buffer->type,
|
209
|
+
handle->memory_usage - Storage::BLOCK_HEADER_SIZE);
|
210
|
+
memcpy(replacement_buffer->buffer, handle->buffer->buffer, handle->buffer->size);
|
211
|
+
memset(handle->buffer->buffer, 165, handle->buffer->size); // 165 is default memory in debug mode
|
212
|
+
handle->buffer = std::move(replacement_buffer);
|
213
|
+
#endif
|
214
|
+
}
|
215
|
+
|
216
|
+
void StandardBufferManager::Unpin(shared_ptr<BlockHandle> &handle) {
|
217
|
+
lock_guard<mutex> lock(handle->lock);
|
218
|
+
if (!handle->buffer || handle->buffer->type == FileBufferType::TINY_BUFFER) {
|
219
|
+
return;
|
220
|
+
}
|
221
|
+
D_ASSERT(handle->readers > 0);
|
222
|
+
handle->readers--;
|
223
|
+
if (handle->readers == 0) {
|
224
|
+
VerifyZeroReaders(handle);
|
225
|
+
buffer_pool.AddToEvictionQueue(handle);
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
// POTENTIALLY PROBLEMATIC
|
230
|
+
void StandardBufferManager::IncreaseUsedMemory(idx_t size, bool unsafe) {
|
231
|
+
ReserveMemory(size);
|
232
|
+
}
|
233
|
+
|
234
|
+
void StandardBufferManager::DecreaseUsedMemory(idx_t size) {
|
235
|
+
FreeReservedMemory(size);
|
236
|
+
}
|
237
|
+
|
238
|
+
void StandardBufferManager::SetLimit(idx_t limit) {
|
239
|
+
buffer_pool.SetLimit(limit, InMemoryWarning());
|
240
|
+
}
|
241
|
+
|
242
|
+
//===--------------------------------------------------------------------===//
|
243
|
+
// Temporary File Management
|
244
|
+
//===--------------------------------------------------------------------===//
|
245
|
+
unique_ptr<FileBuffer> ReadTemporaryBufferInternal(BufferManager &buffer_manager, FileHandle &handle, idx_t position,
|
246
|
+
idx_t size, block_id_t id, unique_ptr<FileBuffer> reusable_buffer) {
|
247
|
+
auto buffer = buffer_manager.ConstructManagedBuffer(size, std::move(reusable_buffer));
|
248
|
+
buffer->Read(handle, position);
|
249
|
+
return buffer;
|
250
|
+
}
|
251
|
+
|
252
|
+
struct TemporaryFileIndex {
|
253
|
+
explicit TemporaryFileIndex(idx_t file_index = DConstants::INVALID_INDEX,
|
254
|
+
idx_t block_index = DConstants::INVALID_INDEX)
|
255
|
+
: file_index(file_index), block_index(block_index) {
|
256
|
+
}
|
257
|
+
|
258
|
+
idx_t file_index;
|
259
|
+
idx_t block_index;
|
260
|
+
|
261
|
+
public:
|
262
|
+
bool IsValid() {
|
263
|
+
return block_index != DConstants::INVALID_INDEX;
|
264
|
+
}
|
265
|
+
};
|
266
|
+
|
267
|
+
struct BlockIndexManager {
|
268
|
+
BlockIndexManager() : max_index(0) {
|
269
|
+
}
|
270
|
+
|
271
|
+
public:
|
272
|
+
//! Obtains a new block index from the index manager
|
273
|
+
idx_t GetNewBlockIndex() {
|
274
|
+
auto index = GetNewBlockIndexInternal();
|
275
|
+
indexes_in_use.insert(index);
|
276
|
+
return index;
|
277
|
+
}
|
278
|
+
|
279
|
+
//! Removes an index from the block manager
|
280
|
+
//! Returns true if the max_index has been altered
|
281
|
+
bool RemoveIndex(idx_t index) {
|
282
|
+
// remove this block from the set of blocks
|
283
|
+
auto entry = indexes_in_use.find(index);
|
284
|
+
if (entry == indexes_in_use.end()) {
|
285
|
+
throw InternalException("RemoveIndex - index %llu not found in indexes_in_use", index);
|
286
|
+
}
|
287
|
+
indexes_in_use.erase(entry);
|
288
|
+
free_indexes.insert(index);
|
289
|
+
// check if we can truncate the file
|
290
|
+
|
291
|
+
// get the max_index in use right now
|
292
|
+
auto max_index_in_use = indexes_in_use.empty() ? 0 : *indexes_in_use.rbegin();
|
293
|
+
if (max_index_in_use < max_index) {
|
294
|
+
// max index in use is lower than the max_index
|
295
|
+
// reduce the max_index
|
296
|
+
max_index = indexes_in_use.empty() ? 0 : max_index_in_use + 1;
|
297
|
+
// we can remove any free_indexes that are larger than the current max_index
|
298
|
+
while (!free_indexes.empty()) {
|
299
|
+
auto max_entry = *free_indexes.rbegin();
|
300
|
+
if (max_entry < max_index) {
|
301
|
+
break;
|
302
|
+
}
|
303
|
+
free_indexes.erase(max_entry);
|
304
|
+
}
|
305
|
+
return true;
|
306
|
+
}
|
307
|
+
return false;
|
308
|
+
}
|
309
|
+
|
310
|
+
idx_t GetMaxIndex() {
|
311
|
+
return max_index;
|
312
|
+
}
|
313
|
+
|
314
|
+
bool HasFreeBlocks() {
|
315
|
+
return !free_indexes.empty();
|
316
|
+
}
|
317
|
+
|
318
|
+
private:
|
319
|
+
idx_t GetNewBlockIndexInternal() {
|
320
|
+
if (free_indexes.empty()) {
|
321
|
+
return max_index++;
|
322
|
+
}
|
323
|
+
auto entry = free_indexes.begin();
|
324
|
+
auto index = *entry;
|
325
|
+
free_indexes.erase(entry);
|
326
|
+
return index;
|
327
|
+
}
|
328
|
+
|
329
|
+
idx_t max_index;
|
330
|
+
set<idx_t> free_indexes;
|
331
|
+
set<idx_t> indexes_in_use;
|
332
|
+
};
|
333
|
+
|
334
|
+
class TemporaryFileHandle {
|
335
|
+
constexpr static idx_t MAX_ALLOWED_INDEX = 4000;
|
336
|
+
|
337
|
+
public:
|
338
|
+
TemporaryFileHandle(DatabaseInstance &db, const string &temp_directory, idx_t index)
|
339
|
+
: db(db), file_index(index), path(FileSystem::GetFileSystem(db).JoinPath(
|
340
|
+
temp_directory, "duckdb_temp_storage-" + to_string(index) + ".tmp")) {
|
341
|
+
}
|
342
|
+
|
343
|
+
public:
|
344
|
+
struct TemporaryFileLock {
|
345
|
+
explicit TemporaryFileLock(mutex &mutex) : lock(mutex) {
|
346
|
+
}
|
347
|
+
|
348
|
+
lock_guard<mutex> lock;
|
349
|
+
};
|
350
|
+
|
351
|
+
public:
|
352
|
+
TemporaryFileIndex TryGetBlockIndex() {
|
353
|
+
TemporaryFileLock lock(file_lock);
|
354
|
+
if (index_manager.GetMaxIndex() >= MAX_ALLOWED_INDEX && index_manager.HasFreeBlocks()) {
|
355
|
+
// file is at capacity
|
356
|
+
return TemporaryFileIndex();
|
357
|
+
}
|
358
|
+
// open the file handle if it does not yet exist
|
359
|
+
CreateFileIfNotExists(lock);
|
360
|
+
// fetch a new block index to write to
|
361
|
+
auto block_index = index_manager.GetNewBlockIndex();
|
362
|
+
return TemporaryFileIndex(file_index, block_index);
|
363
|
+
}
|
364
|
+
|
365
|
+
void WriteTemporaryFile(FileBuffer &buffer, TemporaryFileIndex index) {
|
366
|
+
D_ASSERT(buffer.size == Storage::BLOCK_SIZE);
|
367
|
+
buffer.Write(*handle, GetPositionInFile(index.block_index));
|
368
|
+
}
|
369
|
+
|
370
|
+
unique_ptr<FileBuffer> ReadTemporaryBuffer(block_id_t id, idx_t block_index,
|
371
|
+
unique_ptr<FileBuffer> reusable_buffer) {
|
372
|
+
return ReadTemporaryBufferInternal(BufferManager::GetBufferManager(db), *handle, GetPositionInFile(block_index),
|
373
|
+
Storage::BLOCK_SIZE, id, std::move(reusable_buffer));
|
374
|
+
}
|
375
|
+
|
376
|
+
void EraseBlockIndex(block_id_t block_index) {
|
377
|
+
// remove the block (and potentially truncate the temp file)
|
378
|
+
TemporaryFileLock lock(file_lock);
|
379
|
+
D_ASSERT(handle);
|
380
|
+
RemoveTempBlockIndex(lock, block_index);
|
381
|
+
}
|
382
|
+
|
383
|
+
bool DeleteIfEmpty() {
|
384
|
+
TemporaryFileLock lock(file_lock);
|
385
|
+
if (index_manager.GetMaxIndex() > 0) {
|
386
|
+
// there are still blocks in this file
|
387
|
+
return false;
|
388
|
+
}
|
389
|
+
// the file is empty: delete it
|
390
|
+
handle.reset();
|
391
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
392
|
+
fs.RemoveFile(path);
|
393
|
+
return true;
|
394
|
+
}
|
395
|
+
|
396
|
+
TemporaryFileInformation GetTemporaryFile() {
|
397
|
+
TemporaryFileLock lock(file_lock);
|
398
|
+
TemporaryFileInformation info;
|
399
|
+
info.path = path;
|
400
|
+
info.size = GetPositionInFile(index_manager.GetMaxIndex());
|
401
|
+
return info;
|
402
|
+
}
|
403
|
+
|
404
|
+
private:
|
405
|
+
void CreateFileIfNotExists(TemporaryFileLock &) {
|
406
|
+
if (handle) {
|
407
|
+
return;
|
408
|
+
}
|
409
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
410
|
+
handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_READ | FileFlags::FILE_FLAGS_WRITE |
|
411
|
+
FileFlags::FILE_FLAGS_FILE_CREATE);
|
412
|
+
}
|
413
|
+
|
414
|
+
void RemoveTempBlockIndex(TemporaryFileLock &, idx_t index) {
|
415
|
+
// remove the block index from the index manager
|
416
|
+
if (index_manager.RemoveIndex(index)) {
|
417
|
+
// the max_index that is currently in use has decreased
|
418
|
+
// as a result we can truncate the file
|
419
|
+
#ifndef WIN32 // this ended up causing issues when sorting
|
420
|
+
auto max_index = index_manager.GetMaxIndex();
|
421
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
422
|
+
fs.Truncate(*handle, GetPositionInFile(max_index + 1));
|
423
|
+
#endif
|
424
|
+
}
|
425
|
+
}
|
426
|
+
|
427
|
+
idx_t GetPositionInFile(idx_t index) {
|
428
|
+
return index * Storage::BLOCK_ALLOC_SIZE;
|
429
|
+
}
|
430
|
+
|
431
|
+
private:
|
432
|
+
DatabaseInstance &db;
|
433
|
+
unique_ptr<FileHandle> handle;
|
434
|
+
idx_t file_index;
|
435
|
+
string path;
|
436
|
+
mutex file_lock;
|
437
|
+
BlockIndexManager index_manager;
|
438
|
+
};
|
439
|
+
|
440
|
+
class TemporaryFileManager {
|
441
|
+
public:
|
442
|
+
TemporaryFileManager(DatabaseInstance &db, const string &temp_directory_p)
|
443
|
+
: db(db), temp_directory(temp_directory_p) {
|
444
|
+
}
|
445
|
+
|
446
|
+
public:
|
447
|
+
struct TemporaryManagerLock {
|
448
|
+
explicit TemporaryManagerLock(mutex &mutex) : lock(mutex) {
|
449
|
+
}
|
450
|
+
|
451
|
+
lock_guard<mutex> lock;
|
452
|
+
};
|
453
|
+
|
454
|
+
void WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer) {
|
455
|
+
D_ASSERT(buffer.size == Storage::BLOCK_SIZE);
|
456
|
+
TemporaryFileIndex index;
|
457
|
+
TemporaryFileHandle *handle = nullptr;
|
458
|
+
|
459
|
+
{
|
460
|
+
TemporaryManagerLock lock(manager_lock);
|
461
|
+
// first check if we can write to an open existing file
|
462
|
+
for (auto &entry : files) {
|
463
|
+
auto &temp_file = entry.second;
|
464
|
+
index = temp_file->TryGetBlockIndex();
|
465
|
+
if (index.IsValid()) {
|
466
|
+
handle = entry.second.get();
|
467
|
+
break;
|
468
|
+
}
|
469
|
+
}
|
470
|
+
if (!handle) {
|
471
|
+
// no existing handle to write to; we need to create & open a new file
|
472
|
+
auto new_file_index = index_manager.GetNewBlockIndex();
|
473
|
+
auto new_file = make_uniq<TemporaryFileHandle>(db, temp_directory, new_file_index);
|
474
|
+
handle = new_file.get();
|
475
|
+
files[new_file_index] = std::move(new_file);
|
476
|
+
|
477
|
+
index = handle->TryGetBlockIndex();
|
478
|
+
}
|
479
|
+
D_ASSERT(used_blocks.find(block_id) == used_blocks.end());
|
480
|
+
used_blocks[block_id] = index;
|
481
|
+
}
|
482
|
+
D_ASSERT(handle);
|
483
|
+
D_ASSERT(index.IsValid());
|
484
|
+
handle->WriteTemporaryFile(buffer, index);
|
485
|
+
}
|
486
|
+
|
487
|
+
bool HasTemporaryBuffer(block_id_t block_id) {
|
488
|
+
lock_guard<mutex> lock(manager_lock);
|
489
|
+
return used_blocks.find(block_id) != used_blocks.end();
|
490
|
+
}
|
491
|
+
|
492
|
+
unique_ptr<FileBuffer> ReadTemporaryBuffer(block_id_t id, unique_ptr<FileBuffer> reusable_buffer) {
|
493
|
+
TemporaryFileIndex index;
|
494
|
+
TemporaryFileHandle *handle;
|
495
|
+
{
|
496
|
+
TemporaryManagerLock lock(manager_lock);
|
497
|
+
index = GetTempBlockIndex(lock, id);
|
498
|
+
handle = GetFileHandle(lock, index.file_index);
|
499
|
+
}
|
500
|
+
auto buffer = handle->ReadTemporaryBuffer(id, index.block_index, std::move(reusable_buffer));
|
501
|
+
{
|
502
|
+
// remove the block (and potentially erase the temp file)
|
503
|
+
TemporaryManagerLock lock(manager_lock);
|
504
|
+
EraseUsedBlock(lock, id, handle, index);
|
505
|
+
}
|
506
|
+
return buffer;
|
507
|
+
}
|
508
|
+
|
509
|
+
void DeleteTemporaryBuffer(block_id_t id) {
|
510
|
+
TemporaryManagerLock lock(manager_lock);
|
511
|
+
auto index = GetTempBlockIndex(lock, id);
|
512
|
+
auto handle = GetFileHandle(lock, index.file_index);
|
513
|
+
EraseUsedBlock(lock, id, handle, index);
|
514
|
+
}
|
515
|
+
|
516
|
+
vector<TemporaryFileInformation> GetTemporaryFiles() {
|
517
|
+
lock_guard<mutex> lock(manager_lock);
|
518
|
+
vector<TemporaryFileInformation> result;
|
519
|
+
for (auto &file : files) {
|
520
|
+
result.push_back(file.second->GetTemporaryFile());
|
521
|
+
}
|
522
|
+
return result;
|
523
|
+
}
|
524
|
+
|
525
|
+
private:
|
526
|
+
void EraseUsedBlock(TemporaryManagerLock &lock, block_id_t id, TemporaryFileHandle *handle,
|
527
|
+
TemporaryFileIndex index) {
|
528
|
+
auto entry = used_blocks.find(id);
|
529
|
+
if (entry == used_blocks.end()) {
|
530
|
+
throw InternalException("EraseUsedBlock - Block %llu not found in used blocks", id);
|
531
|
+
}
|
532
|
+
used_blocks.erase(entry);
|
533
|
+
handle->EraseBlockIndex(index.block_index);
|
534
|
+
if (handle->DeleteIfEmpty()) {
|
535
|
+
EraseFileHandle(lock, index.file_index);
|
536
|
+
}
|
537
|
+
}
|
538
|
+
|
539
|
+
TemporaryFileHandle *GetFileHandle(TemporaryManagerLock &, idx_t index) {
|
540
|
+
return files[index].get();
|
541
|
+
}
|
542
|
+
|
543
|
+
TemporaryFileIndex GetTempBlockIndex(TemporaryManagerLock &, block_id_t id) {
|
544
|
+
D_ASSERT(used_blocks.find(id) != used_blocks.end());
|
545
|
+
return used_blocks[id];
|
546
|
+
}
|
547
|
+
|
548
|
+
void EraseFileHandle(TemporaryManagerLock &, idx_t file_index) {
|
549
|
+
files.erase(file_index);
|
550
|
+
index_manager.RemoveIndex(file_index);
|
551
|
+
}
|
552
|
+
|
553
|
+
private:
|
554
|
+
DatabaseInstance &db;
|
555
|
+
mutex manager_lock;
|
556
|
+
//! The temporary directory
|
557
|
+
string temp_directory;
|
558
|
+
//! The set of active temporary file handles
|
559
|
+
unordered_map<idx_t, unique_ptr<TemporaryFileHandle>> files;
|
560
|
+
//! map of block_id -> temporary file position
|
561
|
+
unordered_map<block_id_t, TemporaryFileIndex> used_blocks;
|
562
|
+
//! Manager of in-use temporary file indexes
|
563
|
+
BlockIndexManager index_manager;
|
564
|
+
};
|
565
|
+
|
566
|
+
TemporaryDirectoryHandle::TemporaryDirectoryHandle(DatabaseInstance &db, string path_p)
|
567
|
+
: db(db), temp_directory(std::move(path_p)), temp_file(make_uniq<TemporaryFileManager>(db, temp_directory)) {
|
568
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
569
|
+
if (!temp_directory.empty()) {
|
570
|
+
if (!fs.DirectoryExists(temp_directory)) {
|
571
|
+
fs.CreateDirectory(temp_directory);
|
572
|
+
created_directory = true;
|
573
|
+
}
|
574
|
+
}
|
575
|
+
}
|
576
|
+
TemporaryDirectoryHandle::~TemporaryDirectoryHandle() {
|
577
|
+
// first release any temporary files
|
578
|
+
temp_file.reset();
|
579
|
+
// then delete the temporary file directory
|
580
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
581
|
+
if (!temp_directory.empty()) {
|
582
|
+
bool delete_directory = created_directory;
|
583
|
+
vector<string> files_to_delete;
|
584
|
+
if (!created_directory) {
|
585
|
+
bool deleted_everything = true;
|
586
|
+
fs.ListFiles(temp_directory, [&](const string &path, bool isdir) {
|
587
|
+
if (isdir) {
|
588
|
+
deleted_everything = false;
|
589
|
+
return;
|
590
|
+
}
|
591
|
+
if (!StringUtil::StartsWith(path, "duckdb_temp_")) {
|
592
|
+
deleted_everything = false;
|
593
|
+
return;
|
594
|
+
}
|
595
|
+
files_to_delete.push_back(path);
|
596
|
+
});
|
597
|
+
}
|
598
|
+
if (delete_directory) {
|
599
|
+
// we want to remove all files in the directory
|
600
|
+
fs.RemoveDirectory(temp_directory);
|
601
|
+
} else {
|
602
|
+
for (auto &file : files_to_delete) {
|
603
|
+
fs.RemoveFile(fs.JoinPath(temp_directory, file));
|
604
|
+
}
|
605
|
+
}
|
606
|
+
}
|
607
|
+
}
|
608
|
+
|
609
|
+
TemporaryFileManager &TemporaryDirectoryHandle::GetTempFile() {
|
610
|
+
return *temp_file;
|
611
|
+
}
|
612
|
+
|
613
|
+
string StandardBufferManager::GetTemporaryPath(block_id_t id) {
|
614
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
615
|
+
return fs.JoinPath(temp_directory, "duckdb_temp_block-" + to_string(id) + ".block");
|
616
|
+
}
|
617
|
+
|
618
|
+
void StandardBufferManager::RequireTemporaryDirectory() {
|
619
|
+
if (temp_directory.empty()) {
|
620
|
+
throw Exception(
|
621
|
+
"Out-of-memory: cannot write buffer because no temporary directory is specified!\nTo enable "
|
622
|
+
"temporary buffer eviction set a temporary directory using PRAGMA temp_directory='/path/to/tmp.tmp'");
|
623
|
+
}
|
624
|
+
lock_guard<mutex> temp_handle_guard(temp_handle_lock);
|
625
|
+
if (!temp_directory_handle) {
|
626
|
+
// temp directory has not been created yet: initialize it
|
627
|
+
temp_directory_handle = make_uniq<TemporaryDirectoryHandle>(db, temp_directory);
|
628
|
+
}
|
629
|
+
}
|
630
|
+
|
631
|
+
void StandardBufferManager::WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer) {
|
632
|
+
RequireTemporaryDirectory();
|
633
|
+
if (buffer.size == Storage::BLOCK_SIZE) {
|
634
|
+
temp_directory_handle->GetTempFile().WriteTemporaryBuffer(block_id, buffer);
|
635
|
+
return;
|
636
|
+
}
|
637
|
+
// get the path to write to
|
638
|
+
auto path = GetTemporaryPath(block_id);
|
639
|
+
D_ASSERT(buffer.size > Storage::BLOCK_SIZE);
|
640
|
+
// create the file and write the size followed by the buffer contents
|
641
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
642
|
+
auto handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_FILE_CREATE);
|
643
|
+
handle->Write(&buffer.size, sizeof(idx_t), 0);
|
644
|
+
buffer.Write(*handle, sizeof(idx_t));
|
645
|
+
}
|
646
|
+
|
647
|
+
unique_ptr<FileBuffer> StandardBufferManager::ReadTemporaryBuffer(block_id_t id,
|
648
|
+
unique_ptr<FileBuffer> reusable_buffer) {
|
649
|
+
D_ASSERT(!temp_directory.empty());
|
650
|
+
D_ASSERT(temp_directory_handle.get());
|
651
|
+
if (temp_directory_handle->GetTempFile().HasTemporaryBuffer(id)) {
|
652
|
+
return temp_directory_handle->GetTempFile().ReadTemporaryBuffer(id, std::move(reusable_buffer));
|
653
|
+
}
|
654
|
+
idx_t block_size;
|
655
|
+
// open the temporary file and read the size
|
656
|
+
auto path = GetTemporaryPath(id);
|
657
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
658
|
+
auto handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_READ);
|
659
|
+
handle->Read(&block_size, sizeof(idx_t), 0);
|
660
|
+
|
661
|
+
// now allocate a buffer of this size and read the data into that buffer
|
662
|
+
auto buffer =
|
663
|
+
ReadTemporaryBufferInternal(*this, *handle, sizeof(idx_t), block_size, id, std::move(reusable_buffer));
|
664
|
+
|
665
|
+
handle.reset();
|
666
|
+
DeleteTemporaryFile(id);
|
667
|
+
return buffer;
|
668
|
+
}
|
669
|
+
|
670
|
+
void StandardBufferManager::DeleteTemporaryFile(block_id_t id) {
|
671
|
+
if (temp_directory.empty()) {
|
672
|
+
// no temporary directory specified: nothing to delete
|
673
|
+
return;
|
674
|
+
}
|
675
|
+
{
|
676
|
+
lock_guard<mutex> temp_handle_guard(temp_handle_lock);
|
677
|
+
if (!temp_directory_handle) {
|
678
|
+
// temporary directory was not initialized yet: nothing to delete
|
679
|
+
return;
|
680
|
+
}
|
681
|
+
}
|
682
|
+
// check if we should delete the file from the shared pool of files, or from the general file system
|
683
|
+
if (temp_directory_handle->GetTempFile().HasTemporaryBuffer(id)) {
|
684
|
+
temp_directory_handle->GetTempFile().DeleteTemporaryBuffer(id);
|
685
|
+
return;
|
686
|
+
}
|
687
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
688
|
+
auto path = GetTemporaryPath(id);
|
689
|
+
if (fs.FileExists(path)) {
|
690
|
+
fs.RemoveFile(path);
|
691
|
+
}
|
692
|
+
}
|
693
|
+
|
694
|
+
bool StandardBufferManager::HasTemporaryDirectory() const {
|
695
|
+
return !temp_directory.empty();
|
696
|
+
}
|
697
|
+
|
698
|
+
vector<TemporaryFileInformation> StandardBufferManager::GetTemporaryFiles() {
|
699
|
+
vector<TemporaryFileInformation> result;
|
700
|
+
if (temp_directory.empty()) {
|
701
|
+
return result;
|
702
|
+
}
|
703
|
+
{
|
704
|
+
lock_guard<mutex> temp_handle_guard(temp_handle_lock);
|
705
|
+
if (temp_directory_handle) {
|
706
|
+
result = temp_directory_handle->GetTempFile().GetTemporaryFiles();
|
707
|
+
}
|
708
|
+
}
|
709
|
+
auto &fs = FileSystem::GetFileSystem(db);
|
710
|
+
fs.ListFiles(temp_directory, [&](const string &name, bool is_dir) {
|
711
|
+
if (is_dir) {
|
712
|
+
return;
|
713
|
+
}
|
714
|
+
if (!StringUtil::EndsWith(name, ".block")) {
|
715
|
+
return;
|
716
|
+
}
|
717
|
+
TemporaryFileInformation info;
|
718
|
+
info.path = name;
|
719
|
+
auto handle = fs.OpenFile(name, FileFlags::FILE_FLAGS_READ);
|
720
|
+
info.size = fs.GetFileSize(*handle);
|
721
|
+
handle.reset();
|
722
|
+
result.push_back(info);
|
723
|
+
});
|
724
|
+
return result;
|
725
|
+
}
|
726
|
+
|
727
|
+
const char *StandardBufferManager::InMemoryWarning() {
|
728
|
+
if (!temp_directory.empty()) {
|
729
|
+
return "";
|
730
|
+
}
|
731
|
+
return "\nDatabase is launched in in-memory mode and no temporary directory is specified."
|
732
|
+
"\nUnused blocks cannot be offloaded to disk."
|
733
|
+
"\n\nLaunch the database with a persistent storage back-end"
|
734
|
+
"\nOr set PRAGMA temp_directory='/path/to/tmp.tmp'";
|
735
|
+
}
|
736
|
+
|
737
|
+
void StandardBufferManager::ReserveMemory(idx_t size) {
|
738
|
+
if (size == 0) {
|
739
|
+
return;
|
740
|
+
}
|
741
|
+
auto reservation = EvictBlocksOrThrow(size, nullptr, "failed to reserve memory data of size %lld%s", size);
|
742
|
+
reservation.size = 0;
|
743
|
+
}
|
744
|
+
|
745
|
+
void StandardBufferManager::FreeReservedMemory(idx_t size) {
|
746
|
+
if (size == 0) {
|
747
|
+
return;
|
748
|
+
}
|
749
|
+
buffer_pool.current_memory -= size;
|
750
|
+
}
|
751
|
+
|
752
|
+
//===--------------------------------------------------------------------===//
|
753
|
+
// Buffer Allocator
|
754
|
+
//===--------------------------------------------------------------------===//
|
755
|
+
data_ptr_t StandardBufferManager::BufferAllocatorAllocate(PrivateAllocatorData *private_data, idx_t size) {
|
756
|
+
auto &data = (BufferAllocatorData &)*private_data;
|
757
|
+
auto reservation = data.manager.EvictBlocksOrThrow(size, nullptr, "failed to allocate data of size %lld%s", size);
|
758
|
+
// We rely on manual tracking of this one. :(
|
759
|
+
reservation.size = 0;
|
760
|
+
return Allocator::Get(data.manager.db).AllocateData(size);
|
761
|
+
}
|
762
|
+
|
763
|
+
void StandardBufferManager::BufferAllocatorFree(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t size) {
|
764
|
+
auto &data = (BufferAllocatorData &)*private_data;
|
765
|
+
BufferPoolReservation r(data.manager.GetBufferPool());
|
766
|
+
r.size = size;
|
767
|
+
r.Resize(0);
|
768
|
+
return Allocator::Get(data.manager.db).FreeData(pointer, size);
|
769
|
+
}
|
770
|
+
|
771
|
+
data_ptr_t StandardBufferManager::BufferAllocatorRealloc(PrivateAllocatorData *private_data, data_ptr_t pointer,
|
772
|
+
idx_t old_size, idx_t size) {
|
773
|
+
if (old_size == size) {
|
774
|
+
return pointer;
|
775
|
+
}
|
776
|
+
auto &data = (BufferAllocatorData &)*private_data;
|
777
|
+
BufferPoolReservation r(data.manager.GetBufferPool());
|
778
|
+
r.size = old_size;
|
779
|
+
r.Resize(size);
|
780
|
+
r.size = 0;
|
781
|
+
return Allocator::Get(data.manager.db).ReallocateData(pointer, old_size, size);
|
782
|
+
}
|
783
|
+
|
784
|
+
Allocator &BufferAllocator::Get(ClientContext &context) {
|
785
|
+
auto &manager = StandardBufferManager::GetBufferManager(context);
|
786
|
+
return manager.GetBufferAllocator();
|
787
|
+
}
|
788
|
+
|
789
|
+
Allocator &BufferAllocator::Get(DatabaseInstance &db) {
|
790
|
+
return StandardBufferManager::GetBufferManager(db).GetBufferAllocator();
|
791
|
+
}
|
792
|
+
|
793
|
+
Allocator &BufferAllocator::Get(AttachedDatabase &db) {
|
794
|
+
return BufferAllocator::Get(db.GetDatabase());
|
795
|
+
}
|
796
|
+
|
797
|
+
Allocator &StandardBufferManager::GetBufferAllocator() {
|
798
|
+
return buffer_allocator;
|
799
|
+
}
|
800
|
+
|
801
|
+
} // namespace duckdb
|