duckdb 0.3.3-dev585.0 → 0.3.3-dev681.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.cpp +1292 -481
- package/src/duckdb.hpp +35 -3
- package/src/parquet-amalgamation.cpp +36552 -36552
package/src/duckdb.cpp
CHANGED
|
@@ -34007,28 +34007,68 @@ hash_t Hash(char *val) {
|
|
|
34007
34007
|
return Hash<const char *>(val);
|
|
34008
34008
|
}
|
|
34009
34009
|
|
|
34010
|
-
//
|
|
34011
|
-
|
|
34012
|
-
|
|
34013
|
-
|
|
34014
|
-
|
|
34015
|
-
|
|
34016
|
-
|
|
34017
|
-
|
|
34018
|
-
|
|
34019
|
-
|
|
34020
|
-
|
|
34021
|
-
|
|
34022
|
-
|
|
34010
|
+
// MIT License
|
|
34011
|
+
// Copyright (c) 2018-2021 Martin Ankerl
|
|
34012
|
+
// https://github.com/martinus/robin-hood-hashing/blob/3.11.5/LICENSE
|
|
34013
|
+
hash_t HashBytes(void *ptr, size_t len) noexcept {
|
|
34014
|
+
static constexpr uint64_t M = UINT64_C(0xc6a4a7935bd1e995);
|
|
34015
|
+
static constexpr uint64_t SEED = UINT64_C(0xe17a1465);
|
|
34016
|
+
static constexpr unsigned int R = 47;
|
|
34017
|
+
|
|
34018
|
+
auto const *const data64 = static_cast<uint64_t const *>(ptr);
|
|
34019
|
+
uint64_t h = SEED ^ (len * M);
|
|
34020
|
+
|
|
34021
|
+
size_t const n_blocks = len / 8;
|
|
34022
|
+
for (size_t i = 0; i < n_blocks; ++i) {
|
|
34023
|
+
auto k = Load<uint64_t>(reinterpret_cast<const_data_ptr_t>(data64 + i));
|
|
34024
|
+
|
|
34025
|
+
k *= M;
|
|
34026
|
+
k ^= k >> R;
|
|
34027
|
+
k *= M;
|
|
34028
|
+
|
|
34029
|
+
h ^= k;
|
|
34030
|
+
h *= M;
|
|
34031
|
+
}
|
|
34032
|
+
|
|
34033
|
+
auto const *const data8 = reinterpret_cast<uint8_t const *>(data64 + n_blocks);
|
|
34034
|
+
switch (len & 7U) {
|
|
34035
|
+
case 7:
|
|
34036
|
+
h ^= static_cast<uint64_t>(data8[6]) << 48U;
|
|
34037
|
+
DUCKDB_EXPLICIT_FALLTHROUGH;
|
|
34038
|
+
case 6:
|
|
34039
|
+
h ^= static_cast<uint64_t>(data8[5]) << 40U;
|
|
34040
|
+
DUCKDB_EXPLICIT_FALLTHROUGH;
|
|
34041
|
+
case 5:
|
|
34042
|
+
h ^= static_cast<uint64_t>(data8[4]) << 32U;
|
|
34043
|
+
DUCKDB_EXPLICIT_FALLTHROUGH;
|
|
34044
|
+
case 4:
|
|
34045
|
+
h ^= static_cast<uint64_t>(data8[3]) << 24U;
|
|
34046
|
+
DUCKDB_EXPLICIT_FALLTHROUGH;
|
|
34047
|
+
case 3:
|
|
34048
|
+
h ^= static_cast<uint64_t>(data8[2]) << 16U;
|
|
34049
|
+
DUCKDB_EXPLICIT_FALLTHROUGH;
|
|
34050
|
+
case 2:
|
|
34051
|
+
h ^= static_cast<uint64_t>(data8[1]) << 8U;
|
|
34052
|
+
DUCKDB_EXPLICIT_FALLTHROUGH;
|
|
34053
|
+
case 1:
|
|
34054
|
+
h ^= static_cast<uint64_t>(data8[0]);
|
|
34055
|
+
h *= M;
|
|
34056
|
+
DUCKDB_EXPLICIT_FALLTHROUGH;
|
|
34057
|
+
default:
|
|
34058
|
+
break;
|
|
34059
|
+
}
|
|
34060
|
+
h ^= h >> R;
|
|
34061
|
+
h *= M;
|
|
34062
|
+
h ^= h >> R;
|
|
34063
|
+
return static_cast<hash_t>(h);
|
|
34023
34064
|
}
|
|
34024
34065
|
|
|
34025
34066
|
hash_t Hash(const char *val, size_t size) {
|
|
34026
|
-
|
|
34027
|
-
return Hash<uint32_t>(hash_val);
|
|
34067
|
+
return HashBytes((void *)val, size);
|
|
34028
34068
|
}
|
|
34029
34069
|
|
|
34030
34070
|
hash_t Hash(uint8_t *val, size_t size) {
|
|
34031
|
-
return
|
|
34071
|
+
return HashBytes((void *)val, size);
|
|
34032
34072
|
}
|
|
34033
34073
|
|
|
34034
34074
|
} // namespace duckdb
|
|
@@ -77369,6 +77409,11 @@ struct BitpackingFun {
|
|
|
77369
77409
|
static bool TypeIsSupported(PhysicalType type);
|
|
77370
77410
|
};
|
|
77371
77411
|
|
|
77412
|
+
struct DictionaryCompressionFun {
|
|
77413
|
+
static CompressionFunction GetFunction(PhysicalType type);
|
|
77414
|
+
static bool TypeIsSupported(PhysicalType type);
|
|
77415
|
+
};
|
|
77416
|
+
|
|
77372
77417
|
} // namespace duckdb
|
|
77373
77418
|
|
|
77374
77419
|
|
|
@@ -77389,6 +77434,8 @@ static DefaultCompressionMethod internal_compression_methods[] = {
|
|
|
77389
77434
|
{CompressionType::COMPRESSION_UNCOMPRESSED, UncompressedFun::GetFunction, UncompressedFun::TypeIsSupported},
|
|
77390
77435
|
{CompressionType::COMPRESSION_RLE, RLEFun::GetFunction, RLEFun::TypeIsSupported},
|
|
77391
77436
|
{CompressionType::COMPRESSION_BITPACKING, BitpackingFun::GetFunction, BitpackingFun::TypeIsSupported},
|
|
77437
|
+
{CompressionType::COMPRESSION_DICTIONARY, DictionaryCompressionFun::GetFunction,
|
|
77438
|
+
DictionaryCompressionFun::TypeIsSupported},
|
|
77392
77439
|
{CompressionType::COMPRESSION_AUTO, nullptr, nullptr}};
|
|
77393
77440
|
|
|
77394
77441
|
static CompressionFunction *FindCompressionFunction(CompressionFunctionSet &set, CompressionType type,
|
|
@@ -77438,6 +77485,7 @@ vector<CompressionFunction *> DBConfig::GetCompressionFunctions(PhysicalType dat
|
|
|
77438
77485
|
TryLoadCompression(*this, result, CompressionType::COMPRESSION_UNCOMPRESSED, data_type);
|
|
77439
77486
|
TryLoadCompression(*this, result, CompressionType::COMPRESSION_RLE, data_type);
|
|
77440
77487
|
TryLoadCompression(*this, result, CompressionType::COMPRESSION_BITPACKING, data_type);
|
|
77488
|
+
TryLoadCompression(*this, result, CompressionType::COMPRESSION_DICTIONARY, data_type);
|
|
77441
77489
|
return result;
|
|
77442
77490
|
}
|
|
77443
77491
|
|
|
@@ -160145,6 +160193,16 @@ void PartialBlock::FlushToDisk(DatabaseInstance &db) {
|
|
|
160145
160193
|
}
|
|
160146
160194
|
|
|
160147
160195
|
} // namespace duckdb
|
|
160196
|
+
//===----------------------------------------------------------------------===//
|
|
160197
|
+
// DuckDB
|
|
160198
|
+
//
|
|
160199
|
+
// duckdb/common/bitpacking.hpp
|
|
160200
|
+
//
|
|
160201
|
+
//
|
|
160202
|
+
//===----------------------------------------------------------------------===//
|
|
160203
|
+
|
|
160204
|
+
|
|
160205
|
+
|
|
160148
160206
|
|
|
160149
160207
|
|
|
160150
160208
|
// LICENSE_CHANGE_BEGIN
|
|
@@ -161316,262 +161374,55 @@ inline void fastpack(const uint64_t *__restrict in,
|
|
|
161316
161374
|
|
|
161317
161375
|
|
|
161318
161376
|
|
|
161319
|
-
|
|
161320
|
-
|
|
161321
|
-
//===----------------------------------------------------------------------===//
|
|
161322
|
-
// DuckDB
|
|
161323
|
-
//
|
|
161324
|
-
// duckdb/storage/table/column_data_checkpointer.hpp
|
|
161325
|
-
//
|
|
161326
|
-
//
|
|
161327
|
-
//===----------------------------------------------------------------------===//
|
|
161328
|
-
|
|
161329
|
-
|
|
161330
|
-
|
|
161331
|
-
//===----------------------------------------------------------------------===//
|
|
161332
|
-
// DuckDB
|
|
161333
|
-
//
|
|
161334
|
-
// duckdb/storage/table/column_data.hpp
|
|
161335
|
-
//
|
|
161336
|
-
//
|
|
161337
|
-
//===----------------------------------------------------------------------===//
|
|
161338
|
-
|
|
161339
|
-
|
|
161340
|
-
|
|
161341
|
-
|
|
161342
|
-
|
|
161343
|
-
|
|
161344
|
-
|
|
161345
|
-
|
|
161346
|
-
|
|
161347
|
-
|
|
161348
|
-
//===----------------------------------------------------------------------===//
|
|
161349
|
-
// DuckDB
|
|
161350
|
-
//
|
|
161351
|
-
// duckdb/storage/table/column_checkpoint_state.hpp
|
|
161352
|
-
//
|
|
161353
|
-
//
|
|
161354
|
-
//===----------------------------------------------------------------------===//
|
|
161355
|
-
|
|
161356
|
-
|
|
161357
|
-
|
|
161358
|
-
|
|
161359
|
-
|
|
161360
|
-
|
|
161361
|
-
|
|
161362
|
-
|
|
161363
|
-
|
|
161364
161377
|
namespace duckdb {
|
|
161365
|
-
class ColumnData;
|
|
161366
|
-
class DatabaseInstance;
|
|
161367
|
-
class RowGroup;
|
|
161368
|
-
class TableDataWriter;
|
|
161369
|
-
|
|
161370
|
-
struct ColumnCheckpointState {
|
|
161371
|
-
ColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, TableDataWriter &writer);
|
|
161372
|
-
virtual ~ColumnCheckpointState();
|
|
161373
|
-
|
|
161374
|
-
RowGroup &row_group;
|
|
161375
|
-
ColumnData &column_data;
|
|
161376
|
-
TableDataWriter &writer;
|
|
161377
|
-
SegmentTree new_tree;
|
|
161378
|
-
vector<DataPointer> data_pointers;
|
|
161379
|
-
unique_ptr<BaseStatistics> global_stats;
|
|
161380
|
-
|
|
161381
|
-
public:
|
|
161382
|
-
virtual unique_ptr<BaseStatistics> GetStatistics() {
|
|
161383
|
-
return global_stats->Copy();
|
|
161384
|
-
}
|
|
161385
|
-
|
|
161386
|
-
virtual void FlushSegment(unique_ptr<ColumnSegment> segment, idx_t segment_size);
|
|
161387
|
-
virtual void FlushToDisk();
|
|
161388
|
-
};
|
|
161389
|
-
|
|
161390
|
-
} // namespace duckdb
|
|
161391
|
-
|
|
161392
|
-
|
|
161393
|
-
|
|
161394
|
-
namespace duckdb {
|
|
161395
|
-
class ColumnData;
|
|
161396
|
-
class ColumnSegment;
|
|
161397
|
-
class DatabaseInstance;
|
|
161398
|
-
class RowGroup;
|
|
161399
|
-
class TableDataWriter;
|
|
161400
|
-
class Transaction;
|
|
161401
|
-
|
|
161402
|
-
struct DataTableInfo;
|
|
161403
|
-
|
|
161404
|
-
struct ColumnCheckpointInfo {
|
|
161405
|
-
ColumnCheckpointInfo(CompressionType compression_type_p) : compression_type(compression_type_p) {};
|
|
161406
|
-
CompressionType compression_type;
|
|
161407
|
-
};
|
|
161408
|
-
|
|
161409
|
-
class ColumnData {
|
|
161410
|
-
friend class ColumnDataCheckpointer;
|
|
161411
|
-
|
|
161412
|
-
public:
|
|
161413
|
-
ColumnData(DataTableInfo &info, idx_t column_index, idx_t start_row, LogicalType type, ColumnData *parent);
|
|
161414
|
-
virtual ~ColumnData();
|
|
161415
|
-
|
|
161416
|
-
//! Table info for the column
|
|
161417
|
-
DataTableInfo &info;
|
|
161418
|
-
//! The column index of the column, either within the parent table or within the parent
|
|
161419
|
-
idx_t column_index;
|
|
161420
|
-
//! The start row
|
|
161421
|
-
idx_t start;
|
|
161422
|
-
//! The type of the column
|
|
161423
|
-
LogicalType type;
|
|
161424
|
-
//! The parent column (if any)
|
|
161425
|
-
ColumnData *parent;
|
|
161426
|
-
|
|
161427
|
-
public:
|
|
161428
|
-
virtual bool CheckZonemap(ColumnScanState &state, TableFilter &filter) = 0;
|
|
161429
|
-
|
|
161430
|
-
DatabaseInstance &GetDatabase() const;
|
|
161431
|
-
DataTableInfo &GetTableInfo() const;
|
|
161432
|
-
virtual idx_t GetMaxEntry();
|
|
161433
|
-
|
|
161434
|
-
//! The root type of the column
|
|
161435
|
-
const LogicalType &RootType() const;
|
|
161436
|
-
|
|
161437
|
-
//! Initialize a scan of the column
|
|
161438
|
-
virtual void InitializeScan(ColumnScanState &state);
|
|
161439
|
-
//! Initialize a scan starting at the specified offset
|
|
161440
|
-
virtual void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx);
|
|
161441
|
-
//! Scan the next vector from the column
|
|
161442
|
-
virtual idx_t Scan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result);
|
|
161443
|
-
virtual idx_t ScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, bool allow_updates);
|
|
161444
|
-
virtual void ScanCommittedRange(idx_t row_group_start, idx_t offset_in_row_group, idx_t count, Vector &result);
|
|
161445
|
-
virtual idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count);
|
|
161446
|
-
//! Select
|
|
161447
|
-
virtual void Select(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
|
|
161448
|
-
SelectionVector &sel, idx_t &count, const TableFilter &filter);
|
|
161449
|
-
virtual void FilterScan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
|
|
161450
|
-
SelectionVector &sel, idx_t count);
|
|
161451
|
-
virtual void FilterScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, SelectionVector &sel,
|
|
161452
|
-
idx_t count, bool allow_updates);
|
|
161453
|
-
|
|
161454
|
-
//! Skip the scan forward by "count" rows
|
|
161455
|
-
virtual void Skip(ColumnScanState &state, idx_t count = STANDARD_VECTOR_SIZE);
|
|
161456
|
-
|
|
161457
|
-
//! Initialize an appending phase for this column
|
|
161458
|
-
virtual void InitializeAppend(ColumnAppendState &state);
|
|
161459
|
-
//! Append a vector of type [type] to the end of the column
|
|
161460
|
-
virtual void Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t count);
|
|
161461
|
-
virtual void AppendData(BaseStatistics &stats, ColumnAppendState &state, VectorData &vdata, idx_t count);
|
|
161462
|
-
//! Revert a set of appends to the ColumnData
|
|
161463
|
-
virtual void RevertAppend(row_t start_row);
|
|
161464
|
-
|
|
161465
|
-
//! Fetch the vector from the column data that belongs to this specific row
|
|
161466
|
-
virtual idx_t Fetch(ColumnScanState &state, row_t row_id, Vector &result);
|
|
161467
|
-
//! Fetch a specific row id and append it to the vector
|
|
161468
|
-
virtual void FetchRow(Transaction &transaction, ColumnFetchState &state, row_t row_id, Vector &result,
|
|
161469
|
-
idx_t result_idx);
|
|
161470
|
-
|
|
161471
|
-
virtual void Update(Transaction &transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
|
|
161472
|
-
idx_t update_count);
|
|
161473
|
-
virtual void UpdateColumn(Transaction &transaction, const vector<column_t> &column_path, Vector &update_vector,
|
|
161474
|
-
row_t *row_ids, idx_t update_count, idx_t depth);
|
|
161475
|
-
virtual unique_ptr<BaseStatistics> GetUpdateStatistics();
|
|
161476
|
-
|
|
161477
|
-
virtual void CommitDropColumn();
|
|
161478
|
-
|
|
161479
|
-
virtual unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, TableDataWriter &writer);
|
|
161480
|
-
virtual unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, TableDataWriter &writer,
|
|
161481
|
-
ColumnCheckpointInfo &checkpoint_info);
|
|
161482
|
-
|
|
161483
|
-
virtual void CheckpointScan(ColumnSegment *segment, ColumnScanState &state, idx_t row_group_start, idx_t count,
|
|
161484
|
-
Vector &scan_vector);
|
|
161485
|
-
|
|
161486
|
-
virtual void DeserializeColumn(Deserializer &source);
|
|
161487
|
-
static shared_ptr<ColumnData> Deserialize(DataTableInfo &info, idx_t column_index, idx_t start_row,
|
|
161488
|
-
Deserializer &source, const LogicalType &type, ColumnData *parent);
|
|
161489
|
-
|
|
161490
|
-
virtual void GetStorageInfo(idx_t row_group_index, vector<idx_t> col_path, vector<vector<Value>> &result);
|
|
161491
|
-
virtual void Verify(RowGroup &parent);
|
|
161492
|
-
|
|
161493
|
-
static shared_ptr<ColumnData> CreateColumn(DataTableInfo &info, idx_t column_index, idx_t start_row,
|
|
161494
|
-
const LogicalType &type, ColumnData *parent = nullptr);
|
|
161495
|
-
static unique_ptr<ColumnData> CreateColumnUnique(DataTableInfo &info, idx_t column_index, idx_t start_row,
|
|
161496
|
-
const LogicalType &type, ColumnData *parent = nullptr);
|
|
161497
|
-
|
|
161498
|
-
protected:
|
|
161499
|
-
//! Append a transient segment
|
|
161500
|
-
void AppendTransientSegment(idx_t start_row);
|
|
161501
161378
|
|
|
161502
|
-
|
|
161503
|
-
idx_t ScanVector(ColumnScanState &state, Vector &result, idx_t remaining);
|
|
161504
|
-
//! Scans a vector from the column merged with any potential updates
|
|
161505
|
-
//! If ALLOW_UPDATES is set to false, the function will instead throw an exception if any updates are found
|
|
161506
|
-
template <bool SCAN_COMMITTED, bool ALLOW_UPDATES>
|
|
161507
|
-
idx_t ScanVector(Transaction *transaction, idx_t vector_index, ColumnScanState &state, Vector &result);
|
|
161508
|
-
|
|
161509
|
-
protected:
|
|
161510
|
-
//! The segments holding the data of this column segment
|
|
161511
|
-
SegmentTree data;
|
|
161512
|
-
//! The lock for the updates
|
|
161513
|
-
mutex update_lock;
|
|
161514
|
-
//! The updates for this column segment
|
|
161515
|
-
unique_ptr<UpdateSegment> updates;
|
|
161516
|
-
};
|
|
161517
|
-
|
|
161518
|
-
} // namespace duckdb
|
|
161519
|
-
|
|
161520
|
-
|
|
161521
|
-
|
|
161522
|
-
namespace duckdb {
|
|
161379
|
+
using bitpacking_width_t = uint8_t;
|
|
161523
161380
|
|
|
161524
|
-
class
|
|
161525
|
-
public:
|
|
161526
|
-
ColumnDataCheckpointer(ColumnData &col_data_p, RowGroup &row_group_p, ColumnCheckpointState &state_p,
|
|
161527
|
-
ColumnCheckpointInfo &checkpoint_info);
|
|
161381
|
+
class BitpackingPrimitives {
|
|
161528
161382
|
|
|
161529
161383
|
public:
|
|
161530
|
-
|
|
161531
|
-
const
|
|
161532
|
-
|
|
161533
|
-
RowGroup &GetRowGroup();
|
|
161534
|
-
ColumnCheckpointState &GetCheckpointState();
|
|
161535
|
-
|
|
161536
|
-
void Checkpoint(unique_ptr<SegmentBase> segment);
|
|
161537
|
-
|
|
161538
|
-
private:
|
|
161539
|
-
void ScanSegments(const std::function<void(Vector &, idx_t)> &callback);
|
|
161540
|
-
unique_ptr<AnalyzeState> DetectBestCompressionMethod(idx_t &compression_idx);
|
|
161541
|
-
void WriteToDisk();
|
|
161542
|
-
bool HasChanges();
|
|
161543
|
-
void WritePersistentSegments();
|
|
161544
|
-
|
|
161545
|
-
private:
|
|
161546
|
-
ColumnData &col_data;
|
|
161547
|
-
RowGroup &row_group;
|
|
161548
|
-
ColumnCheckpointState &state;
|
|
161549
|
-
bool is_validity;
|
|
161550
|
-
Vector intermediate;
|
|
161551
|
-
unique_ptr<SegmentBase> owned_segment;
|
|
161552
|
-
vector<CompressionFunction *> compression_functions;
|
|
161553
|
-
ColumnCheckpointInfo &checkpoint_info;
|
|
161554
|
-
};
|
|
161555
|
-
|
|
161556
|
-
} // namespace duckdb
|
|
161557
|
-
|
|
161384
|
+
static constexpr const idx_t BITPACKING_ALGORITHM_GROUP_SIZE = 32;
|
|
161385
|
+
static constexpr const idx_t BITPACKING_HEADER_SIZE = sizeof(uint64_t);
|
|
161386
|
+
static constexpr const bool BYTE_ALIGNED = false;
|
|
161558
161387
|
|
|
161388
|
+
// To ensure enough data is available, use GetRequiredSize() to determine the correct size for dst buffer
|
|
161389
|
+
// Note: input should be aligned to BITPACKING_ALGORITHM_GROUP_SIZE for good performance.
|
|
161390
|
+
template <class T, bool ASSUME_INPUT_ALIGNED = false>
|
|
161391
|
+
inline static void PackBuffer(data_ptr_t dst, T *src, idx_t count, bitpacking_width_t width) {
|
|
161392
|
+
if (ASSUME_INPUT_ALIGNED) {
|
|
161393
|
+
for (idx_t i = 0; i < count; i += BITPACKING_ALGORITHM_GROUP_SIZE) {
|
|
161394
|
+
PackGroup<T>(dst + (i * width) / 8, src + i, width);
|
|
161395
|
+
}
|
|
161396
|
+
} else {
|
|
161397
|
+
idx_t misaligned_count = count % BITPACKING_ALGORITHM_GROUP_SIZE;
|
|
161398
|
+
T tmp_buffer[BITPACKING_ALGORITHM_GROUP_SIZE]; // TODO maybe faster on the heap?
|
|
161559
161399
|
|
|
161560
|
-
|
|
161400
|
+
if (misaligned_count) {
|
|
161401
|
+
count -= misaligned_count;
|
|
161402
|
+
}
|
|
161561
161403
|
|
|
161562
|
-
|
|
161404
|
+
for (idx_t i = 0; i < count; i += BITPACKING_ALGORITHM_GROUP_SIZE) {
|
|
161405
|
+
PackGroup<T>(dst + (i * width) / 8, src + i, width);
|
|
161406
|
+
}
|
|
161563
161407
|
|
|
161564
|
-
|
|
161408
|
+
// Input was not aligned to BITPACKING_ALGORITHM_GROUP_SIZE, we need a copy
|
|
161409
|
+
if (misaligned_count) {
|
|
161410
|
+
memcpy(tmp_buffer, src + count, misaligned_count * sizeof(T));
|
|
161411
|
+
PackGroup<T>(dst + (count * width) / 8, tmp_buffer, width);
|
|
161412
|
+
}
|
|
161413
|
+
}
|
|
161414
|
+
}
|
|
161565
161415
|
|
|
161566
|
-
//
|
|
161567
|
-
//
|
|
161568
|
-
|
|
161416
|
+
// Unpacks a block of BITPACKING_ALGORITHM_GROUP_SIZE values
|
|
161417
|
+
// Assumes both src and dst to be of the correct size
|
|
161418
|
+
template <class T>
|
|
161419
|
+
inline static void UnPackBuffer(data_ptr_t dst, data_ptr_t src, idx_t count, bitpacking_width_t width,
|
|
161420
|
+
bool skip_sign_extension = false) {
|
|
161569
161421
|
|
|
161570
|
-
|
|
161571
|
-
|
|
161572
|
-
|
|
161573
|
-
|
|
161574
|
-
static constexpr const bool BYTE_ALIGNED = false;
|
|
161422
|
+
for (idx_t i = 0; i < count; i += BITPACKING_ALGORITHM_GROUP_SIZE) {
|
|
161423
|
+
UnPackGroup<T>(dst + i * sizeof(T), src + (i * width) / 8, width, skip_sign_extension);
|
|
161424
|
+
}
|
|
161425
|
+
}
|
|
161575
161426
|
|
|
161576
161427
|
// Packs a block of BITPACKING_ALGORITHM_GROUP_SIZE values
|
|
161577
161428
|
template <class T>
|
|
@@ -161586,44 +161437,35 @@ public:
|
|
|
161586
161437
|
return UnPackGroup<T>(dst, src, width, skip_sign_extension);
|
|
161587
161438
|
}
|
|
161588
161439
|
|
|
161440
|
+
// Calculates the minimum required number of bits per value that can store all values
|
|
161441
|
+
template <class T>
|
|
161442
|
+
inline static bitpacking_width_t MinimumBitWidth(T value) {
|
|
161443
|
+
return FindMinimumBitWidth<T, BYTE_ALIGNED>(value, value);
|
|
161444
|
+
}
|
|
161445
|
+
|
|
161589
161446
|
// Calculates the minimum required number of bits per value that can store all values
|
|
161590
161447
|
template <class T>
|
|
161591
161448
|
inline static bitpacking_width_t MinimumBitWidth(T *values, idx_t count) {
|
|
161592
161449
|
return FindMinimumBitWidth<T, BYTE_ALIGNED>(values, count);
|
|
161593
161450
|
}
|
|
161594
161451
|
|
|
161595
|
-
private:
|
|
161596
161452
|
template <class T>
|
|
161597
|
-
static
|
|
161598
|
-
|
|
161599
|
-
|
|
161600
|
-
|
|
161601
|
-
if (min_value == NumericLimits<T>::Minimum()) {
|
|
161602
|
-
// handle special case of the minimal value, as it cannot be negated like all other values.
|
|
161603
|
-
return sizeof(T) * 8;
|
|
161604
|
-
} else {
|
|
161605
|
-
max_value = MaxValue((T)-min_value, max_value);
|
|
161606
|
-
}
|
|
161607
|
-
}
|
|
161608
|
-
|
|
161609
|
-
if (max_value == 0) {
|
|
161610
|
-
return 0;
|
|
161611
|
-
}
|
|
161612
|
-
|
|
161613
|
-
if (std::is_signed<T>::value) {
|
|
161614
|
-
required_bits = 1;
|
|
161615
|
-
} else {
|
|
161616
|
-
required_bits = 0;
|
|
161617
|
-
}
|
|
161453
|
+
inline static idx_t GetRequiredSize(idx_t count, bitpacking_width_t width) {
|
|
161454
|
+
count = RoundUpToAlgorithmGroupSize(count);
|
|
161455
|
+
return ((count * width) / 8);
|
|
161456
|
+
}
|
|
161618
161457
|
|
|
161619
|
-
|
|
161620
|
-
|
|
161621
|
-
|
|
161458
|
+
template <class T>
|
|
161459
|
+
inline static T RoundUpToAlgorithmGroupSize(T num_to_round) {
|
|
161460
|
+
int remainder = num_to_round % BITPACKING_ALGORITHM_GROUP_SIZE;
|
|
161461
|
+
if (remainder == 0) {
|
|
161462
|
+
return num_to_round;
|
|
161622
161463
|
}
|
|
161623
161464
|
|
|
161624
|
-
return
|
|
161465
|
+
return num_to_round + BITPACKING_ALGORITHM_GROUP_SIZE - remainder;
|
|
161625
161466
|
}
|
|
161626
161467
|
|
|
161468
|
+
private:
|
|
161627
161469
|
template <class T, bool round_to_next_byte = false>
|
|
161628
161470
|
static bitpacking_width_t FindMinimumBitWidth(T *values, idx_t count) {
|
|
161629
161471
|
T min_value = values[0];
|
|
@@ -161641,23 +161483,57 @@ private:
|
|
|
161641
161483
|
}
|
|
161642
161484
|
}
|
|
161643
161485
|
|
|
161644
|
-
|
|
161486
|
+
return FindMinimumBitWidth<T, round_to_next_byte>(min_value, max_value);
|
|
161487
|
+
}
|
|
161488
|
+
|
|
161489
|
+
template <class T, bool round_to_next_byte = false>
|
|
161490
|
+
static bitpacking_width_t FindMinimumBitWidth(T min_value, T max_value) {
|
|
161491
|
+
bitpacking_width_t bitwidth;
|
|
161492
|
+
T value;
|
|
161493
|
+
|
|
161494
|
+
if (std::is_signed<T>::value) {
|
|
161495
|
+
if (min_value == NumericLimits<T>::Minimum()) {
|
|
161496
|
+
// handle special case of the minimal value, as it cannot be negated like all other values.
|
|
161497
|
+
return sizeof(T) * 8;
|
|
161498
|
+
} else {
|
|
161499
|
+
value = MaxValue((T)-min_value, max_value);
|
|
161500
|
+
}
|
|
161501
|
+
} else {
|
|
161502
|
+
value = max_value;
|
|
161503
|
+
}
|
|
161504
|
+
|
|
161505
|
+
if (value == 0) {
|
|
161506
|
+
return 0;
|
|
161507
|
+
}
|
|
161508
|
+
|
|
161509
|
+
if (std::is_signed<T>::value) {
|
|
161510
|
+
bitwidth = 1;
|
|
161511
|
+
} else {
|
|
161512
|
+
bitwidth = 0;
|
|
161513
|
+
}
|
|
161514
|
+
|
|
161515
|
+
while (value) {
|
|
161516
|
+
bitwidth++;
|
|
161517
|
+
value >>= 1;
|
|
161518
|
+
}
|
|
161519
|
+
|
|
161520
|
+
bitwidth = GetEffectiveWidth<T>(bitwidth);
|
|
161645
161521
|
|
|
161646
161522
|
// Assert results are correct
|
|
161647
161523
|
#ifdef DEBUG
|
|
161648
|
-
if (
|
|
161524
|
+
if (bitwidth < sizeof(T) * 8 && bitwidth != 0) {
|
|
161649
161525
|
if (std::is_signed<T>::value) {
|
|
161650
|
-
D_ASSERT((int64_t)max_value <= (int64_t)(1L << (
|
|
161651
|
-
D_ASSERT((int64_t)min_value >= (int64_t)(-1 * ((1L << (
|
|
161526
|
+
D_ASSERT((int64_t)max_value <= (int64_t)(1L << (bitwidth - 1)) - 1);
|
|
161527
|
+
D_ASSERT((int64_t)min_value >= (int64_t)(-1 * ((1L << (bitwidth - 1)) - 1) - 1));
|
|
161652
161528
|
} else {
|
|
161653
|
-
D_ASSERT((uint64_t)max_value <= (uint64_t)(1L << (
|
|
161529
|
+
D_ASSERT((uint64_t)max_value <= (uint64_t)(1L << (bitwidth)) - 1);
|
|
161654
161530
|
}
|
|
161655
161531
|
}
|
|
161656
161532
|
#endif
|
|
161657
161533
|
if (round_to_next_byte) {
|
|
161658
|
-
return (
|
|
161534
|
+
return (bitwidth / 8 + (bitwidth % 8 != 0)) * 8;
|
|
161659
161535
|
} else {
|
|
161660
|
-
return
|
|
161536
|
+
return bitwidth;
|
|
161661
161537
|
}
|
|
161662
161538
|
}
|
|
161663
161539
|
|
|
@@ -161727,6 +161603,263 @@ private:
|
|
|
161727
161603
|
}
|
|
161728
161604
|
};
|
|
161729
161605
|
|
|
161606
|
+
} // namespace duckdb
|
|
161607
|
+
|
|
161608
|
+
|
|
161609
|
+
|
|
161610
|
+
|
|
161611
|
+
|
|
161612
|
+
|
|
161613
|
+
|
|
161614
|
+
|
|
161615
|
+
|
|
161616
|
+
//===----------------------------------------------------------------------===//
|
|
161617
|
+
// DuckDB
|
|
161618
|
+
//
|
|
161619
|
+
// duckdb/storage/table/column_data_checkpointer.hpp
|
|
161620
|
+
//
|
|
161621
|
+
//
|
|
161622
|
+
//===----------------------------------------------------------------------===//
|
|
161623
|
+
|
|
161624
|
+
|
|
161625
|
+
|
|
161626
|
+
//===----------------------------------------------------------------------===//
|
|
161627
|
+
// DuckDB
|
|
161628
|
+
//
|
|
161629
|
+
// duckdb/storage/table/column_data.hpp
|
|
161630
|
+
//
|
|
161631
|
+
//
|
|
161632
|
+
//===----------------------------------------------------------------------===//
|
|
161633
|
+
|
|
161634
|
+
|
|
161635
|
+
|
|
161636
|
+
|
|
161637
|
+
|
|
161638
|
+
|
|
161639
|
+
|
|
161640
|
+
|
|
161641
|
+
|
|
161642
|
+
|
|
161643
|
+
//===----------------------------------------------------------------------===//
|
|
161644
|
+
// DuckDB
|
|
161645
|
+
//
|
|
161646
|
+
// duckdb/storage/table/column_checkpoint_state.hpp
|
|
161647
|
+
//
|
|
161648
|
+
//
|
|
161649
|
+
//===----------------------------------------------------------------------===//
|
|
161650
|
+
|
|
161651
|
+
|
|
161652
|
+
|
|
161653
|
+
|
|
161654
|
+
|
|
161655
|
+
|
|
161656
|
+
|
|
161657
|
+
|
|
161658
|
+
|
|
161659
|
+
namespace duckdb {
|
|
161660
|
+
class ColumnData;
|
|
161661
|
+
class DatabaseInstance;
|
|
161662
|
+
class RowGroup;
|
|
161663
|
+
class TableDataWriter;
|
|
161664
|
+
|
|
161665
|
+
struct ColumnCheckpointState {
|
|
161666
|
+
ColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, TableDataWriter &writer);
|
|
161667
|
+
virtual ~ColumnCheckpointState();
|
|
161668
|
+
|
|
161669
|
+
RowGroup &row_group;
|
|
161670
|
+
ColumnData &column_data;
|
|
161671
|
+
TableDataWriter &writer;
|
|
161672
|
+
SegmentTree new_tree;
|
|
161673
|
+
vector<DataPointer> data_pointers;
|
|
161674
|
+
unique_ptr<BaseStatistics> global_stats;
|
|
161675
|
+
|
|
161676
|
+
public:
|
|
161677
|
+
virtual unique_ptr<BaseStatistics> GetStatistics() {
|
|
161678
|
+
return global_stats->Copy();
|
|
161679
|
+
}
|
|
161680
|
+
|
|
161681
|
+
virtual void FlushSegment(unique_ptr<ColumnSegment> segment, idx_t segment_size);
|
|
161682
|
+
virtual void FlushToDisk();
|
|
161683
|
+
};
|
|
161684
|
+
|
|
161685
|
+
} // namespace duckdb
|
|
161686
|
+
|
|
161687
|
+
|
|
161688
|
+
|
|
161689
|
+
namespace duckdb {
|
|
161690
|
+
class ColumnData;
|
|
161691
|
+
class ColumnSegment;
|
|
161692
|
+
class DatabaseInstance;
|
|
161693
|
+
class RowGroup;
|
|
161694
|
+
class TableDataWriter;
|
|
161695
|
+
class Transaction;
|
|
161696
|
+
|
|
161697
|
+
struct DataTableInfo;
|
|
161698
|
+
|
|
161699
|
+
struct ColumnCheckpointInfo {
|
|
161700
|
+
ColumnCheckpointInfo(CompressionType compression_type_p) : compression_type(compression_type_p) {};
|
|
161701
|
+
CompressionType compression_type;
|
|
161702
|
+
};
|
|
161703
|
+
|
|
161704
|
+
class ColumnData {
|
|
161705
|
+
friend class ColumnDataCheckpointer;
|
|
161706
|
+
|
|
161707
|
+
public:
|
|
161708
|
+
ColumnData(DataTableInfo &info, idx_t column_index, idx_t start_row, LogicalType type, ColumnData *parent);
|
|
161709
|
+
virtual ~ColumnData();
|
|
161710
|
+
|
|
161711
|
+
//! Table info for the column
|
|
161712
|
+
DataTableInfo &info;
|
|
161713
|
+
//! The column index of the column, either within the parent table or within the parent
|
|
161714
|
+
idx_t column_index;
|
|
161715
|
+
//! The start row
|
|
161716
|
+
idx_t start;
|
|
161717
|
+
//! The type of the column
|
|
161718
|
+
LogicalType type;
|
|
161719
|
+
//! The parent column (if any)
|
|
161720
|
+
ColumnData *parent;
|
|
161721
|
+
|
|
161722
|
+
public:
|
|
161723
|
+
virtual bool CheckZonemap(ColumnScanState &state, TableFilter &filter) = 0;
|
|
161724
|
+
|
|
161725
|
+
DatabaseInstance &GetDatabase() const;
|
|
161726
|
+
DataTableInfo &GetTableInfo() const;
|
|
161727
|
+
virtual idx_t GetMaxEntry();
|
|
161728
|
+
|
|
161729
|
+
//! The root type of the column
|
|
161730
|
+
const LogicalType &RootType() const;
|
|
161731
|
+
|
|
161732
|
+
//! Initialize a scan of the column
|
|
161733
|
+
virtual void InitializeScan(ColumnScanState &state);
|
|
161734
|
+
//! Initialize a scan starting at the specified offset
|
|
161735
|
+
virtual void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx);
|
|
161736
|
+
//! Scan the next vector from the column
|
|
161737
|
+
virtual idx_t Scan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result);
|
|
161738
|
+
virtual idx_t ScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, bool allow_updates);
|
|
161739
|
+
virtual void ScanCommittedRange(idx_t row_group_start, idx_t offset_in_row_group, idx_t count, Vector &result);
|
|
161740
|
+
virtual idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count);
|
|
161741
|
+
//! Select
|
|
161742
|
+
virtual void Select(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
|
|
161743
|
+
SelectionVector &sel, idx_t &count, const TableFilter &filter);
|
|
161744
|
+
virtual void FilterScan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
|
|
161745
|
+
SelectionVector &sel, idx_t count);
|
|
161746
|
+
virtual void FilterScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, SelectionVector &sel,
|
|
161747
|
+
idx_t count, bool allow_updates);
|
|
161748
|
+
|
|
161749
|
+
//! Skip the scan forward by "count" rows
|
|
161750
|
+
virtual void Skip(ColumnScanState &state, idx_t count = STANDARD_VECTOR_SIZE);
|
|
161751
|
+
|
|
161752
|
+
//! Initialize an appending phase for this column
|
|
161753
|
+
virtual void InitializeAppend(ColumnAppendState &state);
|
|
161754
|
+
//! Append a vector of type [type] to the end of the column
|
|
161755
|
+
virtual void Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t count);
|
|
161756
|
+
virtual void AppendData(BaseStatistics &stats, ColumnAppendState &state, VectorData &vdata, idx_t count);
|
|
161757
|
+
//! Revert a set of appends to the ColumnData
|
|
161758
|
+
virtual void RevertAppend(row_t start_row);
|
|
161759
|
+
|
|
161760
|
+
//! Fetch the vector from the column data that belongs to this specific row
|
|
161761
|
+
virtual idx_t Fetch(ColumnScanState &state, row_t row_id, Vector &result);
|
|
161762
|
+
//! Fetch a specific row id and append it to the vector
|
|
161763
|
+
virtual void FetchRow(Transaction &transaction, ColumnFetchState &state, row_t row_id, Vector &result,
|
|
161764
|
+
idx_t result_idx);
|
|
161765
|
+
|
|
161766
|
+
virtual void Update(Transaction &transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
|
|
161767
|
+
idx_t update_count);
|
|
161768
|
+
virtual void UpdateColumn(Transaction &transaction, const vector<column_t> &column_path, Vector &update_vector,
|
|
161769
|
+
row_t *row_ids, idx_t update_count, idx_t depth);
|
|
161770
|
+
virtual unique_ptr<BaseStatistics> GetUpdateStatistics();
|
|
161771
|
+
|
|
161772
|
+
virtual void CommitDropColumn();
|
|
161773
|
+
|
|
161774
|
+
virtual unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, TableDataWriter &writer);
|
|
161775
|
+
virtual unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, TableDataWriter &writer,
|
|
161776
|
+
ColumnCheckpointInfo &checkpoint_info);
|
|
161777
|
+
|
|
161778
|
+
virtual void CheckpointScan(ColumnSegment *segment, ColumnScanState &state, idx_t row_group_start, idx_t count,
|
|
161779
|
+
Vector &scan_vector);
|
|
161780
|
+
|
|
161781
|
+
virtual void DeserializeColumn(Deserializer &source);
|
|
161782
|
+
static shared_ptr<ColumnData> Deserialize(DataTableInfo &info, idx_t column_index, idx_t start_row,
|
|
161783
|
+
Deserializer &source, const LogicalType &type, ColumnData *parent);
|
|
161784
|
+
|
|
161785
|
+
virtual void GetStorageInfo(idx_t row_group_index, vector<idx_t> col_path, vector<vector<Value>> &result);
|
|
161786
|
+
virtual void Verify(RowGroup &parent);
|
|
161787
|
+
|
|
161788
|
+
static shared_ptr<ColumnData> CreateColumn(DataTableInfo &info, idx_t column_index, idx_t start_row,
|
|
161789
|
+
const LogicalType &type, ColumnData *parent = nullptr);
|
|
161790
|
+
static unique_ptr<ColumnData> CreateColumnUnique(DataTableInfo &info, idx_t column_index, idx_t start_row,
|
|
161791
|
+
const LogicalType &type, ColumnData *parent = nullptr);
|
|
161792
|
+
|
|
161793
|
+
protected:
|
|
161794
|
+
//! Append a transient segment
|
|
161795
|
+
void AppendTransientSegment(idx_t start_row);
|
|
161796
|
+
|
|
161797
|
+
//! Scans a base vector from the column
|
|
161798
|
+
idx_t ScanVector(ColumnScanState &state, Vector &result, idx_t remaining);
|
|
161799
|
+
//! Scans a vector from the column merged with any potential updates
|
|
161800
|
+
//! If ALLOW_UPDATES is set to false, the function will instead throw an exception if any updates are found
|
|
161801
|
+
template <bool SCAN_COMMITTED, bool ALLOW_UPDATES>
|
|
161802
|
+
idx_t ScanVector(Transaction *transaction, idx_t vector_index, ColumnScanState &state, Vector &result);
|
|
161803
|
+
|
|
161804
|
+
protected:
|
|
161805
|
+
//! The segments holding the data of this column segment
|
|
161806
|
+
SegmentTree data;
|
|
161807
|
+
//! The lock for the updates
|
|
161808
|
+
mutex update_lock;
|
|
161809
|
+
//! The updates for this column segment
|
|
161810
|
+
unique_ptr<UpdateSegment> updates;
|
|
161811
|
+
};
|
|
161812
|
+
|
|
161813
|
+
} // namespace duckdb
|
|
161814
|
+
|
|
161815
|
+
|
|
161816
|
+
|
|
161817
|
+
namespace duckdb {
|
|
161818
|
+
|
|
161819
|
+
class ColumnDataCheckpointer {
|
|
161820
|
+
public:
|
|
161821
|
+
ColumnDataCheckpointer(ColumnData &col_data_p, RowGroup &row_group_p, ColumnCheckpointState &state_p,
|
|
161822
|
+
ColumnCheckpointInfo &checkpoint_info);
|
|
161823
|
+
|
|
161824
|
+
public:
|
|
161825
|
+
DatabaseInstance &GetDatabase();
|
|
161826
|
+
const LogicalType &GetType() const;
|
|
161827
|
+
ColumnData &GetColumnData();
|
|
161828
|
+
RowGroup &GetRowGroup();
|
|
161829
|
+
ColumnCheckpointState &GetCheckpointState();
|
|
161830
|
+
|
|
161831
|
+
void Checkpoint(unique_ptr<SegmentBase> segment);
|
|
161832
|
+
|
|
161833
|
+
private:
|
|
161834
|
+
void ScanSegments(const std::function<void(Vector &, idx_t)> &callback);
|
|
161835
|
+
unique_ptr<AnalyzeState> DetectBestCompressionMethod(idx_t &compression_idx);
|
|
161836
|
+
void WriteToDisk();
|
|
161837
|
+
bool HasChanges();
|
|
161838
|
+
void WritePersistentSegments();
|
|
161839
|
+
|
|
161840
|
+
private:
|
|
161841
|
+
ColumnData &col_data;
|
|
161842
|
+
RowGroup &row_group;
|
|
161843
|
+
ColumnCheckpointState &state;
|
|
161844
|
+
bool is_validity;
|
|
161845
|
+
Vector intermediate;
|
|
161846
|
+
unique_ptr<SegmentBase> owned_segment;
|
|
161847
|
+
vector<CompressionFunction *> compression_functions;
|
|
161848
|
+
ColumnCheckpointInfo &checkpoint_info;
|
|
161849
|
+
};
|
|
161850
|
+
|
|
161851
|
+
} // namespace duckdb
|
|
161852
|
+
|
|
161853
|
+
|
|
161854
|
+
|
|
161855
|
+
#include <functional>
|
|
161856
|
+
|
|
161857
|
+
namespace duckdb {
|
|
161858
|
+
|
|
161859
|
+
// Note that optimizations in scanning only work if this value is equal to STANDARD_VECTOR_SIZE, however we keep them
|
|
161860
|
+
// separated to prevent the code from break on lower vector sizes
|
|
161861
|
+
static constexpr const idx_t BITPACKING_WIDTH_GROUP_SIZE = 1024;
|
|
161862
|
+
|
|
161730
161863
|
struct EmptyBitpackingWriter {
|
|
161731
161864
|
template <class T>
|
|
161732
161865
|
static void Operation(T *values, bool *validity, bitpacking_width_t width, idx_t count, void *data_ptr) {
|
|
@@ -161891,12 +162024,8 @@ public:
|
|
|
161891
162024
|
|
|
161892
162025
|
void WriteValues(T *values, bitpacking_width_t width, idx_t count) {
|
|
161893
162026
|
// TODO we can optimize this by stopping early if count < BITPACKING_WIDTH_GROUP_SIZE
|
|
161894
|
-
|
|
161895
|
-
|
|
161896
|
-
BitpackingPrimitives::PackBlock<T>(
|
|
161897
|
-
data_ptr, &values[i * BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE], width);
|
|
161898
|
-
data_ptr += (BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE * width) / 8;
|
|
161899
|
-
}
|
|
162027
|
+
BitpackingPrimitives::PackBuffer<T, false>(data_ptr, values, count, width);
|
|
162028
|
+
data_ptr += (BITPACKING_WIDTH_GROUP_SIZE * width) / 8;
|
|
161900
162029
|
|
|
161901
162030
|
Store<bitpacking_width_t>(width, width_ptr);
|
|
161902
162031
|
width_ptr -= sizeof(bitpacking_width_t);
|
|
@@ -162181,6 +162310,11 @@ bool BitpackingFun::TypeIsSupported(PhysicalType type) {
|
|
|
162181
162310
|
}
|
|
162182
162311
|
|
|
162183
162312
|
} // namespace duckdb
|
|
162313
|
+
|
|
162314
|
+
|
|
162315
|
+
|
|
162316
|
+
|
|
162317
|
+
|
|
162184
162318
|
//===----------------------------------------------------------------------===//
|
|
162185
162319
|
// DuckDB
|
|
162186
162320
|
//
|
|
@@ -162241,6 +162375,842 @@ public:
|
|
|
162241
162375
|
|
|
162242
162376
|
|
|
162243
162377
|
|
|
162378
|
+
|
|
162379
|
+
|
|
162380
|
+
|
|
162381
|
+
|
|
162382
|
+
|
|
162383
|
+
namespace duckdb {
|
|
162384
|
+
struct StringDictionaryContainer {
|
|
162385
|
+
//! The size of the dictionary
|
|
162386
|
+
uint32_t size;
|
|
162387
|
+
//! The end of the dictionary (typically Storage::BLOCK_SIZE)
|
|
162388
|
+
uint32_t end;
|
|
162389
|
+
|
|
162390
|
+
void Verify() {
|
|
162391
|
+
D_ASSERT(size <= Storage::BLOCK_SIZE);
|
|
162392
|
+
D_ASSERT(end <= Storage::BLOCK_SIZE);
|
|
162393
|
+
D_ASSERT(size <= end);
|
|
162394
|
+
}
|
|
162395
|
+
};
|
|
162396
|
+
|
|
162397
|
+
struct StringScanState : public SegmentScanState {
|
|
162398
|
+
unique_ptr<BufferHandle> handle;
|
|
162399
|
+
};
|
|
162400
|
+
|
|
162401
|
+
struct UncompressedStringStorage {
|
|
162402
|
+
public:
|
|
162403
|
+
//! Dictionary header size at the beginning of the string segment (offset + length)
|
|
162404
|
+
static constexpr uint16_t DICTIONARY_HEADER_SIZE = sizeof(uint32_t) + sizeof(uint32_t);
|
|
162405
|
+
//! Marker used in length field to indicate the presence of a big string
|
|
162406
|
+
static constexpr uint16_t BIG_STRING_MARKER = (uint16_t)-1;
|
|
162407
|
+
//! Base size of big string marker (block id + offset)
|
|
162408
|
+
static constexpr idx_t BIG_STRING_MARKER_BASE_SIZE = sizeof(block_id_t) + sizeof(int32_t);
|
|
162409
|
+
//! The marker size of the big string
|
|
162410
|
+
static constexpr idx_t BIG_STRING_MARKER_SIZE = BIG_STRING_MARKER_BASE_SIZE + sizeof(uint16_t);
|
|
162411
|
+
//! The size below which the segment is compacted on flushing
|
|
162412
|
+
static constexpr size_t COMPACTION_FLUSH_LIMIT = (size_t)Storage::BLOCK_SIZE / 5 * 4;
|
|
162413
|
+
|
|
162414
|
+
public:
|
|
162415
|
+
static unique_ptr<AnalyzeState> StringInitAnalyze(ColumnData &col_data, PhysicalType type);
|
|
162416
|
+
static bool StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count);
|
|
162417
|
+
static idx_t StringFinalAnalyze(AnalyzeState &state_p);
|
|
162418
|
+
static unique_ptr<SegmentScanState> StringInitScan(ColumnSegment &segment);
|
|
162419
|
+
static void StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result,
|
|
162420
|
+
idx_t result_offset);
|
|
162421
|
+
static void StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result);
|
|
162422
|
+
static void StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result,
|
|
162423
|
+
idx_t result_idx);
|
|
162424
|
+
static unique_ptr<CompressedSegmentState> StringInitSegment(ColumnSegment &segment, block_id_t block_id);
|
|
162425
|
+
|
|
162426
|
+
static idx_t StringAppend(ColumnSegment &segment, SegmentStatistics &stats, VectorData &data, idx_t offset,
|
|
162427
|
+
idx_t count) {
|
|
162428
|
+
return StringAppendBase(segment, stats, data, offset, count);
|
|
162429
|
+
}
|
|
162430
|
+
|
|
162431
|
+
template <bool DUPLICATE_ELIMINATE = false>
|
|
162432
|
+
static idx_t StringAppendBase(ColumnSegment &segment, SegmentStatistics &stats, VectorData &data, idx_t offset,
|
|
162433
|
+
idx_t count, std::unordered_map<string, int32_t> *seen_strings = nullptr) {
|
|
162434
|
+
auto &buffer_manager = BufferManager::GetBufferManager(segment.db);
|
|
162435
|
+
auto handle = buffer_manager.Pin(segment.block);
|
|
162436
|
+
|
|
162437
|
+
D_ASSERT(segment.GetBlockOffset() == 0);
|
|
162438
|
+
auto source_data = (string_t *)data.data;
|
|
162439
|
+
auto result_data = (int32_t *)(handle->node->buffer + DICTIONARY_HEADER_SIZE);
|
|
162440
|
+
for (idx_t i = 0; i < count; i++) {
|
|
162441
|
+
auto source_idx = data.sel->get_index(offset + i);
|
|
162442
|
+
auto target_idx = segment.count.load();
|
|
162443
|
+
idx_t remaining_space = RemainingSpace(segment, *handle);
|
|
162444
|
+
if (remaining_space < sizeof(int32_t)) {
|
|
162445
|
+
// string index does not fit in the block at all
|
|
162446
|
+
return i;
|
|
162447
|
+
}
|
|
162448
|
+
remaining_space -= sizeof(int32_t);
|
|
162449
|
+
if (!data.validity.RowIsValid(source_idx)) {
|
|
162450
|
+
// null value is stored as -1
|
|
162451
|
+
result_data[target_idx] = 0;
|
|
162452
|
+
} else {
|
|
162453
|
+
auto dictionary = GetDictionary(segment, *handle);
|
|
162454
|
+
auto end = handle->node->buffer + dictionary.end;
|
|
162455
|
+
|
|
162456
|
+
dictionary.Verify();
|
|
162457
|
+
|
|
162458
|
+
int32_t match;
|
|
162459
|
+
bool found;
|
|
162460
|
+
if (DUPLICATE_ELIMINATE) {
|
|
162461
|
+
auto search = seen_strings->find(source_data[source_idx].GetString());
|
|
162462
|
+
if (search != seen_strings->end()) {
|
|
162463
|
+
match = search->second;
|
|
162464
|
+
found = true;
|
|
162465
|
+
} else {
|
|
162466
|
+
found = false;
|
|
162467
|
+
}
|
|
162468
|
+
}
|
|
162469
|
+
|
|
162470
|
+
if (DUPLICATE_ELIMINATE && found) {
|
|
162471
|
+
// We have seen this string
|
|
162472
|
+
result_data[target_idx] = match;
|
|
162473
|
+
} else {
|
|
162474
|
+
// Unknown string, continue
|
|
162475
|
+
// non-null value, check if we can fit it within the block
|
|
162476
|
+
idx_t string_length = source_data[source_idx].GetSize();
|
|
162477
|
+
idx_t dictionary_length = string_length + sizeof(uint16_t);
|
|
162478
|
+
|
|
162479
|
+
// determine whether or not we have space in the block for this string
|
|
162480
|
+
bool use_overflow_block = false;
|
|
162481
|
+
idx_t required_space = dictionary_length;
|
|
162482
|
+
if (required_space >= StringUncompressed::STRING_BLOCK_LIMIT) {
|
|
162483
|
+
// string exceeds block limit, store in overflow block and only write a marker here
|
|
162484
|
+
required_space = BIG_STRING_MARKER_SIZE;
|
|
162485
|
+
use_overflow_block = true;
|
|
162486
|
+
}
|
|
162487
|
+
if (required_space > remaining_space) {
|
|
162488
|
+
// no space remaining: return how many tuples we ended up writing
|
|
162489
|
+
return i;
|
|
162490
|
+
}
|
|
162491
|
+
|
|
162492
|
+
// we have space: write the string
|
|
162493
|
+
UpdateStringStats(stats, source_data[source_idx]);
|
|
162494
|
+
|
|
162495
|
+
if (use_overflow_block) {
|
|
162496
|
+
// write to overflow blocks
|
|
162497
|
+
block_id_t block;
|
|
162498
|
+
int32_t offset;
|
|
162499
|
+
// write the string into the current string block
|
|
162500
|
+
WriteString(segment, source_data[source_idx], block, offset);
|
|
162501
|
+
dictionary.size += BIG_STRING_MARKER_SIZE;
|
|
162502
|
+
auto dict_pos = end - dictionary.size;
|
|
162503
|
+
|
|
162504
|
+
// write a big string marker into the dictionary
|
|
162505
|
+
WriteStringMarker(dict_pos, block, offset);
|
|
162506
|
+
} else {
|
|
162507
|
+
// string fits in block, append to dictionary and increment dictionary position
|
|
162508
|
+
D_ASSERT(string_length < NumericLimits<uint16_t>::Maximum());
|
|
162509
|
+
dictionary.size += required_space;
|
|
162510
|
+
auto dict_pos = end - dictionary.size; // first write the length as u16
|
|
162511
|
+
Store<uint16_t>(string_length, dict_pos);
|
|
162512
|
+
// now write the actual string data into the dictionary
|
|
162513
|
+
memcpy(dict_pos + sizeof(uint16_t), source_data[source_idx].GetDataUnsafe(), string_length);
|
|
162514
|
+
}
|
|
162515
|
+
D_ASSERT(RemainingSpace(segment, *handle) <= Storage::BLOCK_SIZE);
|
|
162516
|
+
// place the dictionary offset into the set of vectors
|
|
162517
|
+
dictionary.Verify();
|
|
162518
|
+
|
|
162519
|
+
result_data[target_idx] = dictionary.size;
|
|
162520
|
+
if (DUPLICATE_ELIMINATE) {
|
|
162521
|
+
seen_strings->insert({source_data[source_idx].GetString(), dictionary.size});
|
|
162522
|
+
}
|
|
162523
|
+
SetDictionary(segment, *handle, dictionary);
|
|
162524
|
+
}
|
|
162525
|
+
}
|
|
162526
|
+
segment.count++;
|
|
162527
|
+
}
|
|
162528
|
+
return count;
|
|
162529
|
+
}
|
|
162530
|
+
|
|
162531
|
+
static idx_t FinalizeAppend(ColumnSegment &segment, SegmentStatistics &stats);
|
|
162532
|
+
|
|
162533
|
+
public:
|
|
162534
|
+
static inline void UpdateStringStats(SegmentStatistics &stats, const string_t &new_value) {
|
|
162535
|
+
auto &sstats = (StringStatistics &)*stats.statistics;
|
|
162536
|
+
sstats.Update(new_value);
|
|
162537
|
+
}
|
|
162538
|
+
|
|
162539
|
+
static void SetDictionary(ColumnSegment &segment, BufferHandle &handle, StringDictionaryContainer dict);
|
|
162540
|
+
static StringDictionaryContainer GetDictionary(ColumnSegment &segment, BufferHandle &handle);
|
|
162541
|
+
static idx_t RemainingSpace(ColumnSegment &segment, BufferHandle &handle);
|
|
162542
|
+
static void WriteString(ColumnSegment &segment, string_t string, block_id_t &result_block, int32_t &result_offset);
|
|
162543
|
+
static void WriteStringMemory(ColumnSegment &segment, string_t string, block_id_t &result_block,
|
|
162544
|
+
int32_t &result_offset);
|
|
162545
|
+
static string_t ReadString(ColumnSegment &segment, Vector &result, block_id_t block, int32_t offset);
|
|
162546
|
+
static string_t ReadString(data_ptr_t target, int32_t offset);
|
|
162547
|
+
static void WriteStringMarker(data_ptr_t target, block_id_t block_id, int32_t offset);
|
|
162548
|
+
static void ReadStringMarker(data_ptr_t target, block_id_t &block_id, int32_t &offset);
|
|
162549
|
+
|
|
162550
|
+
static string_location_t FetchStringLocation(StringDictionaryContainer dict, data_ptr_t baseptr,
|
|
162551
|
+
int32_t dict_offset);
|
|
162552
|
+
static string_t FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result,
|
|
162553
|
+
data_ptr_t baseptr, int32_t dict_offset);
|
|
162554
|
+
static string_t FetchString(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result,
|
|
162555
|
+
data_ptr_t baseptr, string_location_t location);
|
|
162556
|
+
};
|
|
162557
|
+
} // namespace duckdb
|
|
162558
|
+
|
|
162559
|
+
|
|
162560
|
+
|
|
162561
|
+
namespace duckdb {
|
|
162562
|
+
|
|
162563
|
+
struct StringHash {
|
|
162564
|
+
std::size_t operator()(const string_t &k) const {
|
|
162565
|
+
return Hash(k.GetDataUnsafe(), k.GetSize());
|
|
162566
|
+
}
|
|
162567
|
+
};
|
|
162568
|
+
|
|
162569
|
+
struct StringCompare {
|
|
162570
|
+
bool operator()(const string_t &lhs, const string_t &rhs) const {
|
|
162571
|
+
return StringComparisonOperators::EqualsOrNot<false>(lhs, rhs);
|
|
162572
|
+
}
|
|
162573
|
+
};
|
|
162574
|
+
|
|
162575
|
+
// Abstract class for keeping compression state either for compression or size analysis
|
|
162576
|
+
class DictionaryCompressionState : public CompressionState {
|
|
162577
|
+
public:
|
|
162578
|
+
bool UpdateState(Vector &scan_vector, idx_t count) {
|
|
162579
|
+
VectorData vdata;
|
|
162580
|
+
scan_vector.Orrify(count, vdata);
|
|
162581
|
+
auto data = (string_t *)vdata.data;
|
|
162582
|
+
Verify();
|
|
162583
|
+
|
|
162584
|
+
for (idx_t i = 0; i < count; i++) {
|
|
162585
|
+
auto idx = vdata.sel->get_index(i);
|
|
162586
|
+
size_t string_size = 0;
|
|
162587
|
+
bool new_string = false;
|
|
162588
|
+
auto row_is_valid = vdata.validity.RowIsValid(idx);
|
|
162589
|
+
|
|
162590
|
+
if (row_is_valid) {
|
|
162591
|
+
string_size = data[idx].GetSize();
|
|
162592
|
+
if (string_size >= StringUncompressed::STRING_BLOCK_LIMIT) {
|
|
162593
|
+
// Big strings not implemented for dictionary compression
|
|
162594
|
+
return false;
|
|
162595
|
+
}
|
|
162596
|
+
new_string = !LookupString(data[idx]);
|
|
162597
|
+
}
|
|
162598
|
+
|
|
162599
|
+
bool fits = HasEnoughSpace(new_string, string_size);
|
|
162600
|
+
if (!fits) {
|
|
162601
|
+
Flush();
|
|
162602
|
+
new_string = true;
|
|
162603
|
+
D_ASSERT(HasEnoughSpace(new_string, string_size));
|
|
162604
|
+
}
|
|
162605
|
+
|
|
162606
|
+
if (!row_is_valid) {
|
|
162607
|
+
AddNull();
|
|
162608
|
+
} else if (new_string) {
|
|
162609
|
+
AddNewString(data[idx]);
|
|
162610
|
+
} else {
|
|
162611
|
+
AddLastLookup();
|
|
162612
|
+
}
|
|
162613
|
+
|
|
162614
|
+
Verify();
|
|
162615
|
+
}
|
|
162616
|
+
|
|
162617
|
+
return true;
|
|
162618
|
+
}
|
|
162619
|
+
|
|
162620
|
+
protected:
|
|
162621
|
+
// Should verify the State
|
|
162622
|
+
virtual void Verify() = 0;
|
|
162623
|
+
// Performs a lookup of str, storing the result internally
|
|
162624
|
+
virtual bool LookupString(string_t str) = 0;
|
|
162625
|
+
// Add the most recently looked up str to compression state
|
|
162626
|
+
virtual void AddLastLookup() = 0;
|
|
162627
|
+
// Add string to the state that is known to not be seen yet
|
|
162628
|
+
virtual void AddNewString(string_t str) = 0;
|
|
162629
|
+
// Add a null value to the compression state
|
|
162630
|
+
virtual void AddNull() = 0;
|
|
162631
|
+
// Check if we have enough space to add a string
|
|
162632
|
+
virtual bool HasEnoughSpace(bool new_string, size_t string_size) = 0;
|
|
162633
|
+
// Flush the segment to disk if compressing or reset the counters if analyzing
|
|
162634
|
+
virtual void Flush(bool final = false) = 0;
|
|
162635
|
+
};
|
|
162636
|
+
|
|
162637
|
+
typedef struct {
|
|
162638
|
+
uint32_t dict_size;
|
|
162639
|
+
uint32_t dict_end;
|
|
162640
|
+
uint32_t index_buffer_offset;
|
|
162641
|
+
uint32_t index_buffer_count;
|
|
162642
|
+
uint32_t bitpacking_width;
|
|
162643
|
+
} dictionary_compression_header_t;
|
|
162644
|
+
|
|
162645
|
+
struct DictionaryCompressionStorage {
|
|
162646
|
+
static constexpr float MINIMUM_COMPRESSION_RATIO = 1.2;
|
|
162647
|
+
static constexpr uint16_t DICTIONARY_HEADER_SIZE = sizeof(dictionary_compression_header_t);
|
|
162648
|
+
static constexpr size_t COMPACTION_FLUSH_LIMIT = (size_t)Storage::BLOCK_SIZE / 5 * 4;
|
|
162649
|
+
|
|
162650
|
+
static unique_ptr<AnalyzeState> StringInitAnalyze(ColumnData &col_data, PhysicalType type);
|
|
162651
|
+
static bool StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count);
|
|
162652
|
+
static idx_t StringFinalAnalyze(AnalyzeState &state_p);
|
|
162653
|
+
|
|
162654
|
+
static unique_ptr<CompressionState> InitCompression(ColumnDataCheckpointer &checkpointer,
|
|
162655
|
+
unique_ptr<AnalyzeState> state);
|
|
162656
|
+
static void Compress(CompressionState &state_p, Vector &scan_vector, idx_t count);
|
|
162657
|
+
static void FinalizeCompress(CompressionState &state_p);
|
|
162658
|
+
|
|
162659
|
+
static unique_ptr<SegmentScanState> StringInitScan(ColumnSegment &segment);
|
|
162660
|
+
template <bool ALLOW_DICT_VECTORS>
|
|
162661
|
+
static void StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result,
|
|
162662
|
+
idx_t result_offset);
|
|
162663
|
+
static void StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result);
|
|
162664
|
+
static void StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result,
|
|
162665
|
+
idx_t result_idx);
|
|
162666
|
+
|
|
162667
|
+
static bool HasEnoughSpace(idx_t current_count, idx_t index_count, idx_t dict_size,
|
|
162668
|
+
bitpacking_width_t packing_width);
|
|
162669
|
+
static idx_t RequiredSpace(idx_t current_count, idx_t index_count, idx_t dict_size,
|
|
162670
|
+
bitpacking_width_t packing_width);
|
|
162671
|
+
|
|
162672
|
+
static StringDictionaryContainer GetDictionary(ColumnSegment &segment, BufferHandle &handle);
|
|
162673
|
+
static void SetDictionary(ColumnSegment &segment, BufferHandle &handle, StringDictionaryContainer container);
|
|
162674
|
+
static string_t FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, data_ptr_t baseptr,
|
|
162675
|
+
int32_t dict_offset, uint16_t string_len);
|
|
162676
|
+
static uint16_t GetStringLength(uint32_t *index_buffer_ptr, sel_t index);
|
|
162677
|
+
};
|
|
162678
|
+
|
|
162679
|
+
// Dictionary compression uses a combination of bitpacking and a dictionary to compress string segments. The data is
|
|
162680
|
+
// stored across three buffers: the index buffer, the selection buffer and the dictionary. Firstly the Index buffer
|
|
162681
|
+
// contains the offsets into the dictionary which are also used to determine the string lengths. Each value in the
|
|
162682
|
+
// dictionary gets a single unique index in the index buffer. Secondly, the selection buffer maps the tuples to an index
|
|
162683
|
+
// in the index buffer. The selection buffer is compressed with bitpacking. Finally, the dictionary contains simply all
|
|
162684
|
+
// the unique strings without lenghts or null termination as we can deduce the lengths from the index buffer. The
|
|
162685
|
+
// addition of the selection buffer is done for two reasons: firstly, to allow the scan to emit dictionary vectors by
|
|
162686
|
+
// scanning the whole dictionary at once and then scanning the selection buffer for each emitted vector. Secondly, it
|
|
162687
|
+
// allows for efficient bitpacking compression as the selection values should remain relatively small.
|
|
162688
|
+
struct DictionaryCompressionCompressState : public DictionaryCompressionState {
|
|
162689
|
+
explicit DictionaryCompressionCompressState(ColumnDataCheckpointer &checkpointer) : checkpointer(checkpointer) {
|
|
162690
|
+
auto &db = checkpointer.GetDatabase();
|
|
162691
|
+
auto &config = DBConfig::GetConfig(db);
|
|
162692
|
+
function = config.GetCompressionFunction(CompressionType::COMPRESSION_DICTIONARY, PhysicalType::VARCHAR);
|
|
162693
|
+
CreateEmptySegment(checkpointer.GetRowGroup().start);
|
|
162694
|
+
}
|
|
162695
|
+
|
|
162696
|
+
void CreateEmptySegment(idx_t row_start) {
|
|
162697
|
+
auto &db = checkpointer.GetDatabase();
|
|
162698
|
+
auto &type = checkpointer.GetType();
|
|
162699
|
+
auto compressed_segment = ColumnSegment::CreateTransientSegment(db, type, row_start);
|
|
162700
|
+
current_segment = move(compressed_segment);
|
|
162701
|
+
|
|
162702
|
+
current_segment->function = function;
|
|
162703
|
+
|
|
162704
|
+
// Reset the buffers and string map
|
|
162705
|
+
current_string_map.clear();
|
|
162706
|
+
index_buffer.clear();
|
|
162707
|
+
index_buffer.push_back(0); // Reserve index 0 for null strings
|
|
162708
|
+
selection_buffer.clear();
|
|
162709
|
+
|
|
162710
|
+
current_width = 0;
|
|
162711
|
+
next_width = 0;
|
|
162712
|
+
|
|
162713
|
+
// Reset the pointers into the current segment
|
|
162714
|
+
auto &buffer_manager = BufferManager::GetBufferManager(current_segment->db);
|
|
162715
|
+
current_handle = buffer_manager.Pin(current_segment->block);
|
|
162716
|
+
current_dictionary = DictionaryCompressionStorage::GetDictionary(*current_segment, *current_handle);
|
|
162717
|
+
current_end_ptr = current_handle->node->buffer + current_dictionary.end;
|
|
162718
|
+
}
|
|
162719
|
+
|
|
162720
|
+
ColumnDataCheckpointer &checkpointer;
|
|
162721
|
+
CompressionFunction *function;
|
|
162722
|
+
|
|
162723
|
+
// State regarding current segment
|
|
162724
|
+
unique_ptr<ColumnSegment> current_segment;
|
|
162725
|
+
unique_ptr<BufferHandle> current_handle;
|
|
162726
|
+
StringDictionaryContainer current_dictionary;
|
|
162727
|
+
data_ptr_t current_end_ptr;
|
|
162728
|
+
|
|
162729
|
+
// Buffers and map for current segment
|
|
162730
|
+
std::unordered_map<string_t, uint32_t, StringHash, StringCompare> current_string_map;
|
|
162731
|
+
std::vector<uint32_t> index_buffer;
|
|
162732
|
+
std::vector<uint32_t> selection_buffer;
|
|
162733
|
+
|
|
162734
|
+
bitpacking_width_t current_width = 0;
|
|
162735
|
+
bitpacking_width_t next_width = 0;
|
|
162736
|
+
|
|
162737
|
+
// Result of latest LookupString call
|
|
162738
|
+
uint32_t latest_lookup_result;
|
|
162739
|
+
|
|
162740
|
+
void Verify() override {
|
|
162741
|
+
current_dictionary.Verify();
|
|
162742
|
+
D_ASSERT(current_segment->count == selection_buffer.size());
|
|
162743
|
+
D_ASSERT(DictionaryCompressionStorage::HasEnoughSpace(current_segment->count.load(), index_buffer.size(),
|
|
162744
|
+
current_dictionary.size, current_width));
|
|
162745
|
+
D_ASSERT(current_dictionary.end == Storage::BLOCK_SIZE);
|
|
162746
|
+
D_ASSERT(index_buffer.size() == current_string_map.size() + 1); // +1 is for null value
|
|
162747
|
+
}
|
|
162748
|
+
|
|
162749
|
+
bool LookupString(string_t str) override {
|
|
162750
|
+
auto search = current_string_map.find(str);
|
|
162751
|
+
auto has_result = search != current_string_map.end();
|
|
162752
|
+
|
|
162753
|
+
if (has_result) {
|
|
162754
|
+
latest_lookup_result = search->second;
|
|
162755
|
+
}
|
|
162756
|
+
return has_result;
|
|
162757
|
+
}
|
|
162758
|
+
|
|
162759
|
+
void AddNewString(string_t str) override {
|
|
162760
|
+
UncompressedStringStorage::UpdateStringStats(current_segment->stats, str);
|
|
162761
|
+
|
|
162762
|
+
// Copy string to dict
|
|
162763
|
+
current_dictionary.size += str.GetSize();
|
|
162764
|
+
auto dict_pos = current_end_ptr - current_dictionary.size;
|
|
162765
|
+
memcpy(dict_pos, str.GetDataUnsafe(), str.GetSize());
|
|
162766
|
+
current_dictionary.Verify();
|
|
162767
|
+
D_ASSERT(current_dictionary.end == Storage::BLOCK_SIZE);
|
|
162768
|
+
|
|
162769
|
+
// Update buffers and map
|
|
162770
|
+
index_buffer.push_back(current_dictionary.size);
|
|
162771
|
+
selection_buffer.push_back(index_buffer.size() - 1);
|
|
162772
|
+
current_string_map.insert({str, index_buffer.size() - 1});
|
|
162773
|
+
DictionaryCompressionStorage::SetDictionary(*current_segment, *current_handle, current_dictionary);
|
|
162774
|
+
|
|
162775
|
+
current_width = next_width;
|
|
162776
|
+
current_segment->count++;
|
|
162777
|
+
}
|
|
162778
|
+
|
|
162779
|
+
void AddNull() override {
|
|
162780
|
+
selection_buffer.push_back(0);
|
|
162781
|
+
current_segment->count++;
|
|
162782
|
+
}
|
|
162783
|
+
|
|
162784
|
+
void AddLastLookup() override {
|
|
162785
|
+
selection_buffer.push_back(latest_lookup_result);
|
|
162786
|
+
current_segment->count++;
|
|
162787
|
+
}
|
|
162788
|
+
|
|
162789
|
+
bool HasEnoughSpace(bool new_string, size_t string_size) override {
|
|
162790
|
+
if (new_string) {
|
|
162791
|
+
next_width = BitpackingPrimitives::MinimumBitWidth(index_buffer.size() - 1 + new_string);
|
|
162792
|
+
return DictionaryCompressionStorage::HasEnoughSpace(current_segment->count.load() + 1,
|
|
162793
|
+
index_buffer.size() + 1,
|
|
162794
|
+
current_dictionary.size + string_size, next_width);
|
|
162795
|
+
} else {
|
|
162796
|
+
return DictionaryCompressionStorage::HasEnoughSpace(current_segment->count.load() + 1, index_buffer.size(),
|
|
162797
|
+
current_dictionary.size, current_width);
|
|
162798
|
+
}
|
|
162799
|
+
}
|
|
162800
|
+
|
|
162801
|
+
void Flush(bool final = false) override {
|
|
162802
|
+
auto next_start = current_segment->start + current_segment->count;
|
|
162803
|
+
|
|
162804
|
+
auto segment_size = Finalize();
|
|
162805
|
+
auto &state = checkpointer.GetCheckpointState();
|
|
162806
|
+
state.FlushSegment(move(current_segment), segment_size);
|
|
162807
|
+
|
|
162808
|
+
if (!final) {
|
|
162809
|
+
CreateEmptySegment(next_start);
|
|
162810
|
+
}
|
|
162811
|
+
}
|
|
162812
|
+
|
|
162813
|
+
idx_t Finalize() {
|
|
162814
|
+
auto &buffer_manager = BufferManager::GetBufferManager(current_segment->db);
|
|
162815
|
+
auto handle = buffer_manager.Pin(current_segment->block);
|
|
162816
|
+
D_ASSERT(current_dictionary.end == Storage::BLOCK_SIZE);
|
|
162817
|
+
|
|
162818
|
+
// calculate sizes
|
|
162819
|
+
auto compressed_selection_buffer_size =
|
|
162820
|
+
BitpackingPrimitives::GetRequiredSize<sel_t>(current_segment->count, current_width);
|
|
162821
|
+
auto index_buffer_size = index_buffer.size() * sizeof(uint32_t);
|
|
162822
|
+
auto total_size = DictionaryCompressionStorage::DICTIONARY_HEADER_SIZE + compressed_selection_buffer_size +
|
|
162823
|
+
index_buffer_size + current_dictionary.size;
|
|
162824
|
+
|
|
162825
|
+
// calculate ptr and offsets
|
|
162826
|
+
auto base_ptr = handle->node->buffer;
|
|
162827
|
+
auto header_ptr = (dictionary_compression_header_t *)base_ptr;
|
|
162828
|
+
auto compressed_selection_buffer_offset = DictionaryCompressionStorage::DICTIONARY_HEADER_SIZE;
|
|
162829
|
+
auto index_buffer_offset = compressed_selection_buffer_offset + compressed_selection_buffer_size;
|
|
162830
|
+
|
|
162831
|
+
// Write compressed selection buffer
|
|
162832
|
+
BitpackingPrimitives::PackBuffer<sel_t, false>(base_ptr + compressed_selection_buffer_offset,
|
|
162833
|
+
(sel_t *)(selection_buffer.data()), current_segment->count,
|
|
162834
|
+
current_width);
|
|
162835
|
+
|
|
162836
|
+
// Write the index buffer
|
|
162837
|
+
memcpy(base_ptr + index_buffer_offset, index_buffer.data(), index_buffer_size);
|
|
162838
|
+
|
|
162839
|
+
// Store sizes and offsets in segment header
|
|
162840
|
+
Store<uint32_t>(index_buffer_offset, (data_ptr_t)&header_ptr->index_buffer_offset);
|
|
162841
|
+
Store<uint32_t>(index_buffer.size(), (data_ptr_t)&header_ptr->index_buffer_count);
|
|
162842
|
+
Store<uint32_t>((uint32_t)current_width, (data_ptr_t)&header_ptr->bitpacking_width);
|
|
162843
|
+
|
|
162844
|
+
D_ASSERT(current_width == BitpackingPrimitives::MinimumBitWidth(index_buffer.size() - 1));
|
|
162845
|
+
D_ASSERT(DictionaryCompressionStorage::HasEnoughSpace(current_segment->count, index_buffer.size(),
|
|
162846
|
+
current_dictionary.size, current_width));
|
|
162847
|
+
D_ASSERT((uint64_t)*max_element(std::begin(selection_buffer), std::end(selection_buffer)) ==
|
|
162848
|
+
index_buffer.size() - 1);
|
|
162849
|
+
|
|
162850
|
+
if (total_size >= DictionaryCompressionStorage::COMPACTION_FLUSH_LIMIT) {
|
|
162851
|
+
// the block is full enough, don't bother moving around the dictionary
|
|
162852
|
+
return Storage::BLOCK_SIZE;
|
|
162853
|
+
}
|
|
162854
|
+
// the block has space left: figure out how much space we can save
|
|
162855
|
+
auto move_amount = Storage::BLOCK_SIZE - total_size;
|
|
162856
|
+
// move the dictionary so it lines up exactly with the offsets
|
|
162857
|
+
auto new_dictionary_offset = index_buffer_offset + index_buffer_size;
|
|
162858
|
+
memmove(base_ptr + new_dictionary_offset, base_ptr + current_dictionary.end - current_dictionary.size,
|
|
162859
|
+
current_dictionary.size);
|
|
162860
|
+
current_dictionary.end -= move_amount;
|
|
162861
|
+
D_ASSERT(current_dictionary.end == total_size);
|
|
162862
|
+
// write the new dictionary (with the updated "end")
|
|
162863
|
+
DictionaryCompressionStorage::SetDictionary(*current_segment, *handle, current_dictionary);
|
|
162864
|
+
return total_size;
|
|
162865
|
+
}
|
|
162866
|
+
};
|
|
162867
|
+
|
|
162868
|
+
//===--------------------------------------------------------------------===//
|
|
162869
|
+
// Analyze
|
|
162870
|
+
//===--------------------------------------------------------------------===//
|
|
162871
|
+
struct DictionaryCompressionAnalyzeState : public AnalyzeState, DictionaryCompressionState {
|
|
162872
|
+
DictionaryCompressionAnalyzeState()
|
|
162873
|
+
: segment_count(0), current_tuple_count(0), current_unique_count(0), current_dict_size(0), current_width(0),
|
|
162874
|
+
next_width(0) {
|
|
162875
|
+
}
|
|
162876
|
+
|
|
162877
|
+
size_t segment_count;
|
|
162878
|
+
idx_t current_tuple_count;
|
|
162879
|
+
idx_t current_unique_count;
|
|
162880
|
+
size_t current_dict_size;
|
|
162881
|
+
std::unordered_set<string_t, StringHash, StringCompare> current_set;
|
|
162882
|
+
bitpacking_width_t current_width;
|
|
162883
|
+
bitpacking_width_t next_width;
|
|
162884
|
+
|
|
162885
|
+
bool LookupString(string_t str) override {
|
|
162886
|
+
return current_set.count(str);
|
|
162887
|
+
}
|
|
162888
|
+
|
|
162889
|
+
void AddNewString(string_t str) override {
|
|
162890
|
+
current_tuple_count++;
|
|
162891
|
+
current_unique_count++;
|
|
162892
|
+
current_dict_size += str.GetSize();
|
|
162893
|
+
current_set.insert(str);
|
|
162894
|
+
current_width = next_width;
|
|
162895
|
+
}
|
|
162896
|
+
|
|
162897
|
+
void AddLastLookup() override {
|
|
162898
|
+
current_tuple_count++;
|
|
162899
|
+
}
|
|
162900
|
+
|
|
162901
|
+
void AddNull() override {
|
|
162902
|
+
current_tuple_count++;
|
|
162903
|
+
}
|
|
162904
|
+
|
|
162905
|
+
bool HasEnoughSpace(bool new_string, size_t string_size) override {
|
|
162906
|
+
if (new_string) {
|
|
162907
|
+
next_width =
|
|
162908
|
+
BitpackingPrimitives::MinimumBitWidth(current_unique_count + 2); // 1 for null, one for new string
|
|
162909
|
+
return DictionaryCompressionStorage::HasEnoughSpace(current_tuple_count + 1, current_unique_count + 1,
|
|
162910
|
+
current_dict_size + string_size, next_width);
|
|
162911
|
+
} else {
|
|
162912
|
+
return DictionaryCompressionStorage::HasEnoughSpace(current_tuple_count + 1, current_unique_count,
|
|
162913
|
+
current_dict_size, current_width);
|
|
162914
|
+
}
|
|
162915
|
+
}
|
|
162916
|
+
|
|
162917
|
+
void Flush(bool final = false) override {
|
|
162918
|
+
segment_count++;
|
|
162919
|
+
current_tuple_count = 0;
|
|
162920
|
+
current_unique_count = 0;
|
|
162921
|
+
current_dict_size = 0;
|
|
162922
|
+
current_set.clear();
|
|
162923
|
+
}
|
|
162924
|
+
void Verify() override {};
|
|
162925
|
+
};
|
|
162926
|
+
|
|
162927
|
+
unique_ptr<AnalyzeState> DictionaryCompressionStorage::StringInitAnalyze(ColumnData &col_data, PhysicalType type) {
|
|
162928
|
+
return make_unique<DictionaryCompressionAnalyzeState>();
|
|
162929
|
+
}
|
|
162930
|
+
|
|
162931
|
+
bool DictionaryCompressionStorage::StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count) {
|
|
162932
|
+
auto &state = (DictionaryCompressionAnalyzeState &)state_p;
|
|
162933
|
+
return state.UpdateState(input, count);
|
|
162934
|
+
}
|
|
162935
|
+
|
|
162936
|
+
idx_t DictionaryCompressionStorage::StringFinalAnalyze(AnalyzeState &state_p) {
|
|
162937
|
+
auto &state = (DictionaryCompressionAnalyzeState &)state_p;
|
|
162938
|
+
|
|
162939
|
+
auto width = BitpackingPrimitives::MinimumBitWidth(state.current_unique_count + 1);
|
|
162940
|
+
auto req_space =
|
|
162941
|
+
RequiredSpace(state.current_tuple_count, state.current_unique_count, state.current_dict_size, width);
|
|
162942
|
+
|
|
162943
|
+
return MINIMUM_COMPRESSION_RATIO * (state.segment_count * Storage::BLOCK_SIZE + req_space);
|
|
162944
|
+
}
|
|
162945
|
+
|
|
162946
|
+
//===--------------------------------------------------------------------===//
|
|
162947
|
+
// Compress
|
|
162948
|
+
//===--------------------------------------------------------------------===//
|
|
162949
|
+
unique_ptr<CompressionState> DictionaryCompressionStorage::InitCompression(ColumnDataCheckpointer &checkpointer,
|
|
162950
|
+
unique_ptr<AnalyzeState> state) {
|
|
162951
|
+
return make_unique<DictionaryCompressionCompressState>(checkpointer);
|
|
162952
|
+
}
|
|
162953
|
+
|
|
162954
|
+
void DictionaryCompressionStorage::Compress(CompressionState &state_p, Vector &scan_vector, idx_t count) {
|
|
162955
|
+
auto &state = (DictionaryCompressionCompressState &)state_p;
|
|
162956
|
+
state.UpdateState(scan_vector, count);
|
|
162957
|
+
}
|
|
162958
|
+
|
|
162959
|
+
void DictionaryCompressionStorage::FinalizeCompress(CompressionState &state_p) {
|
|
162960
|
+
auto &state = (DictionaryCompressionCompressState &)state_p;
|
|
162961
|
+
state.Flush(true);
|
|
162962
|
+
}
|
|
162963
|
+
|
|
162964
|
+
//===--------------------------------------------------------------------===//
|
|
162965
|
+
// Scan
|
|
162966
|
+
//===--------------------------------------------------------------------===//
|
|
162967
|
+
struct CompressedStringScanState : public StringScanState {
|
|
162968
|
+
unique_ptr<BufferHandle> handle;
|
|
162969
|
+
buffer_ptr<Vector> dictionary;
|
|
162970
|
+
bitpacking_width_t current_width;
|
|
162971
|
+
buffer_ptr<SelectionVector> sel_vec;
|
|
162972
|
+
idx_t sel_vec_size = 0;
|
|
162973
|
+
};
|
|
162974
|
+
|
|
162975
|
+
unique_ptr<SegmentScanState> DictionaryCompressionStorage::StringInitScan(ColumnSegment &segment) {
|
|
162976
|
+
auto state = make_unique<CompressedStringScanState>();
|
|
162977
|
+
auto &buffer_manager = BufferManager::GetBufferManager(segment.db);
|
|
162978
|
+
state->handle = buffer_manager.Pin(segment.block);
|
|
162979
|
+
|
|
162980
|
+
auto baseptr = state->handle->node->buffer + segment.GetBlockOffset();
|
|
162981
|
+
|
|
162982
|
+
// Load header values
|
|
162983
|
+
auto dict = DictionaryCompressionStorage::GetDictionary(segment, *(state->handle));
|
|
162984
|
+
auto header_ptr = (dictionary_compression_header_t *)baseptr;
|
|
162985
|
+
auto index_buffer_offset = Load<uint32_t>((data_ptr_t)&header_ptr->index_buffer_offset);
|
|
162986
|
+
auto index_buffer_count = Load<uint32_t>((data_ptr_t)&header_ptr->index_buffer_count);
|
|
162987
|
+
state->current_width = (bitpacking_width_t)(Load<uint32_t>((data_ptr_t)&header_ptr->bitpacking_width));
|
|
162988
|
+
|
|
162989
|
+
auto index_buffer_ptr = (uint32_t *)(baseptr + index_buffer_offset);
|
|
162990
|
+
|
|
162991
|
+
state->dictionary = make_buffer<Vector>(segment.type, index_buffer_count);
|
|
162992
|
+
auto dict_child_data = FlatVector::GetData<string_t>(*(state->dictionary));
|
|
162993
|
+
|
|
162994
|
+
for (uint32_t i = 0; i < index_buffer_count; i++) {
|
|
162995
|
+
// NOTE: the passing of dict_child_vector, will not be used, its for big strings
|
|
162996
|
+
uint16_t str_len = GetStringLength(index_buffer_ptr, i);
|
|
162997
|
+
dict_child_data[i] = FetchStringFromDict(segment, dict, baseptr, index_buffer_ptr[i], str_len);
|
|
162998
|
+
}
|
|
162999
|
+
|
|
163000
|
+
return move(state);
|
|
163001
|
+
}
|
|
163002
|
+
|
|
163003
|
+
//===--------------------------------------------------------------------===//
|
|
163004
|
+
// Scan base data
|
|
163005
|
+
//===--------------------------------------------------------------------===//
|
|
163006
|
+
template <bool ALLOW_DICT_VECTORS>
|
|
163007
|
+
void DictionaryCompressionStorage::StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count,
|
|
163008
|
+
Vector &result, idx_t result_offset) {
|
|
163009
|
+
// clear any previously locked buffers and get the primary buffer handle
|
|
163010
|
+
auto &scan_state = (CompressedStringScanState &)*state.scan_state;
|
|
163011
|
+
auto start = segment.GetRelativeIndex(state.row_index);
|
|
163012
|
+
|
|
163013
|
+
auto baseptr = scan_state.handle->node->buffer + segment.GetBlockOffset();
|
|
163014
|
+
auto dict = DictionaryCompressionStorage::GetDictionary(segment, *scan_state.handle);
|
|
163015
|
+
|
|
163016
|
+
auto header_ptr = (dictionary_compression_header_t *)baseptr;
|
|
163017
|
+
auto index_buffer_offset = Load<uint32_t>((data_ptr_t)&header_ptr->index_buffer_offset);
|
|
163018
|
+
auto index_buffer_ptr = (uint32_t *)(baseptr + index_buffer_offset);
|
|
163019
|
+
|
|
163020
|
+
auto base_data = (data_ptr_t)(baseptr + DICTIONARY_HEADER_SIZE);
|
|
163021
|
+
auto result_data = FlatVector::GetData<string_t>(result);
|
|
163022
|
+
|
|
163023
|
+
if (!ALLOW_DICT_VECTORS || scan_count != STANDARD_VECTOR_SIZE ||
|
|
163024
|
+
start % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE != 0) {
|
|
163025
|
+
// Emit regular vector
|
|
163026
|
+
|
|
163027
|
+
// Handling non-bitpacking-group-aligned start values;
|
|
163028
|
+
idx_t start_offset = start % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE;
|
|
163029
|
+
|
|
163030
|
+
// We will scan in blocks of BITPACKING_ALGORITHM_GROUP_SIZE, so we may scan some extra values.
|
|
163031
|
+
idx_t decompress_count = BitpackingPrimitives::RoundUpToAlgorithmGroupSize(scan_count + start_offset);
|
|
163032
|
+
|
|
163033
|
+
// Create a decompression buffer of sufficient size if we don't already have one.
|
|
163034
|
+
if (!scan_state.sel_vec || scan_state.sel_vec_size < decompress_count) {
|
|
163035
|
+
scan_state.sel_vec_size = decompress_count;
|
|
163036
|
+
scan_state.sel_vec = make_buffer<SelectionVector>(decompress_count);
|
|
163037
|
+
}
|
|
163038
|
+
|
|
163039
|
+
data_ptr_t src = &base_data[((start - start_offset) * scan_state.current_width) / 8];
|
|
163040
|
+
sel_t *sel_vec_ptr = scan_state.sel_vec->data();
|
|
163041
|
+
|
|
163042
|
+
BitpackingPrimitives::UnPackBuffer<sel_t>((data_ptr_t)sel_vec_ptr, src, decompress_count,
|
|
163043
|
+
scan_state.current_width);
|
|
163044
|
+
|
|
163045
|
+
for (idx_t i = 0; i < scan_count; i++) {
|
|
163046
|
+
// Lookup dict offset in index buffer
|
|
163047
|
+
auto string_number = scan_state.sel_vec->get_index(i + start_offset);
|
|
163048
|
+
auto dict_offset = index_buffer_ptr[string_number];
|
|
163049
|
+
uint16_t str_len = GetStringLength(index_buffer_ptr, string_number);
|
|
163050
|
+
result_data[result_offset + i] = FetchStringFromDict(segment, dict, baseptr, dict_offset, str_len);
|
|
163051
|
+
}
|
|
163052
|
+
|
|
163053
|
+
} else {
|
|
163054
|
+
D_ASSERT(start % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0);
|
|
163055
|
+
D_ASSERT(scan_count == STANDARD_VECTOR_SIZE);
|
|
163056
|
+
D_ASSERT(result_offset == 0);
|
|
163057
|
+
|
|
163058
|
+
idx_t decompress_count = BitpackingPrimitives::RoundUpToAlgorithmGroupSize(scan_count);
|
|
163059
|
+
|
|
163060
|
+
// Create a selection vector of sufficient size if we don't already have one.
|
|
163061
|
+
if (!scan_state.sel_vec || scan_state.sel_vec_size < decompress_count) {
|
|
163062
|
+
scan_state.sel_vec_size = decompress_count;
|
|
163063
|
+
scan_state.sel_vec = make_buffer<SelectionVector>(decompress_count);
|
|
163064
|
+
}
|
|
163065
|
+
|
|
163066
|
+
// Scanning 1024 values, emitting a dict vector
|
|
163067
|
+
data_ptr_t dst = (data_ptr_t)(scan_state.sel_vec->data());
|
|
163068
|
+
data_ptr_t src = (data_ptr_t)&base_data[(start * scan_state.current_width) / 8];
|
|
163069
|
+
|
|
163070
|
+
BitpackingPrimitives::UnPackBuffer<sel_t>(dst, src, scan_count, scan_state.current_width);
|
|
163071
|
+
|
|
163072
|
+
result.Slice(*(scan_state.dictionary), *scan_state.sel_vec, scan_count);
|
|
163073
|
+
}
|
|
163074
|
+
}
|
|
163075
|
+
|
|
163076
|
+
void DictionaryCompressionStorage::StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count,
|
|
163077
|
+
Vector &result) {
|
|
163078
|
+
StringScanPartial<true>(segment, state, scan_count, result, 0);
|
|
163079
|
+
}
|
|
163080
|
+
|
|
163081
|
+
//===--------------------------------------------------------------------===//
|
|
163082
|
+
// Fetch
|
|
163083
|
+
//===--------------------------------------------------------------------===//
|
|
163084
|
+
void DictionaryCompressionStorage::StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id,
|
|
163085
|
+
Vector &result, idx_t result_idx) {
|
|
163086
|
+
// fetch a single row from the string segment
|
|
163087
|
+
// first pin the main buffer if it is not already pinned
|
|
163088
|
+
auto primary_id = segment.block->BlockId();
|
|
163089
|
+
|
|
163090
|
+
BufferHandle *handle_ptr;
|
|
163091
|
+
auto entry = state.handles.find(primary_id);
|
|
163092
|
+
if (entry == state.handles.end()) {
|
|
163093
|
+
// not pinned yet: pin it
|
|
163094
|
+
auto &buffer_manager = BufferManager::GetBufferManager(segment.db);
|
|
163095
|
+
auto handle = buffer_manager.Pin(segment.block);
|
|
163096
|
+
handle_ptr = handle.get();
|
|
163097
|
+
state.handles[primary_id] = move(handle);
|
|
163098
|
+
} else {
|
|
163099
|
+
// already pinned: use the pinned handle
|
|
163100
|
+
handle_ptr = entry->second.get();
|
|
163101
|
+
}
|
|
163102
|
+
|
|
163103
|
+
auto baseptr = handle_ptr->node->buffer + segment.GetBlockOffset();
|
|
163104
|
+
auto header_ptr = (dictionary_compression_header_t *)baseptr;
|
|
163105
|
+
auto dict = DictionaryCompressionStorage::GetDictionary(segment, *handle_ptr);
|
|
163106
|
+
auto index_buffer_offset = Load<uint32_t>((data_ptr_t)&header_ptr->index_buffer_offset);
|
|
163107
|
+
auto width = (bitpacking_width_t)(Load<uint32_t>((data_ptr_t)&header_ptr->bitpacking_width));
|
|
163108
|
+
auto index_buffer_ptr = (uint32_t *)(baseptr + index_buffer_offset);
|
|
163109
|
+
auto base_data = (data_ptr_t)(baseptr + DICTIONARY_HEADER_SIZE);
|
|
163110
|
+
auto result_data = FlatVector::GetData<string_t>(result);
|
|
163111
|
+
|
|
163112
|
+
// Handling non-bitpacking-group-aligned start values;
|
|
163113
|
+
idx_t start_offset = row_id % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE;
|
|
163114
|
+
|
|
163115
|
+
// Decompress part of selection buffer we need for this value.
|
|
163116
|
+
sel_t decompression_buffer[BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE];
|
|
163117
|
+
data_ptr_t src = (data_ptr_t)&base_data[((row_id - start_offset) * width) / 8];
|
|
163118
|
+
BitpackingPrimitives::UnPackBuffer<sel_t>((data_ptr_t)decompression_buffer, src,
|
|
163119
|
+
BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE, width);
|
|
163120
|
+
|
|
163121
|
+
auto selection_value = decompression_buffer[start_offset];
|
|
163122
|
+
auto dict_offset = index_buffer_ptr[selection_value];
|
|
163123
|
+
uint16_t str_len = GetStringLength(index_buffer_ptr, selection_value);
|
|
163124
|
+
|
|
163125
|
+
result_data[result_idx] = FetchStringFromDict(segment, dict, baseptr, dict_offset, str_len);
|
|
163126
|
+
}
|
|
163127
|
+
|
|
163128
|
+
//===--------------------------------------------------------------------===//
|
|
163129
|
+
// Helper Functions
|
|
163130
|
+
//===--------------------------------------------------------------------===//
|
|
163131
|
+
bool DictionaryCompressionStorage::HasEnoughSpace(idx_t current_count, idx_t index_count, idx_t dict_size,
|
|
163132
|
+
bitpacking_width_t packing_width) {
|
|
163133
|
+
return RequiredSpace(current_count, index_count, dict_size, packing_width) <= Storage::BLOCK_SIZE;
|
|
163134
|
+
}
|
|
163135
|
+
|
|
163136
|
+
idx_t DictionaryCompressionStorage::RequiredSpace(idx_t current_count, idx_t index_count, idx_t dict_size,
|
|
163137
|
+
bitpacking_width_t packing_width) {
|
|
163138
|
+
idx_t base_space = DICTIONARY_HEADER_SIZE + dict_size;
|
|
163139
|
+
idx_t string_number_space = BitpackingPrimitives::GetRequiredSize<sel_t>(current_count, packing_width);
|
|
163140
|
+
idx_t index_space = index_count * sizeof(uint32_t);
|
|
163141
|
+
|
|
163142
|
+
idx_t used_space = base_space + index_space + string_number_space;
|
|
163143
|
+
|
|
163144
|
+
return used_space;
|
|
163145
|
+
}
|
|
163146
|
+
|
|
163147
|
+
StringDictionaryContainer DictionaryCompressionStorage::GetDictionary(ColumnSegment &segment, BufferHandle &handle) {
|
|
163148
|
+
auto header_ptr = (dictionary_compression_header_t *)(handle.node->buffer + segment.GetBlockOffset());
|
|
163149
|
+
StringDictionaryContainer container;
|
|
163150
|
+
container.size = Load<uint32_t>((data_ptr_t)&header_ptr->dict_size);
|
|
163151
|
+
container.end = Load<uint32_t>((data_ptr_t)&header_ptr->dict_end);
|
|
163152
|
+
return container;
|
|
163153
|
+
}
|
|
163154
|
+
|
|
163155
|
+
void DictionaryCompressionStorage::SetDictionary(ColumnSegment &segment, BufferHandle &handle,
|
|
163156
|
+
StringDictionaryContainer container) {
|
|
163157
|
+
auto header_ptr = (dictionary_compression_header_t *)(handle.node->buffer + segment.GetBlockOffset());
|
|
163158
|
+
Store<uint32_t>(container.size, (data_ptr_t)&header_ptr->dict_size);
|
|
163159
|
+
Store<uint32_t>(container.end, (data_ptr_t)&header_ptr->dict_end);
|
|
163160
|
+
}
|
|
163161
|
+
|
|
163162
|
+
string_t DictionaryCompressionStorage::FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict,
|
|
163163
|
+
data_ptr_t baseptr, int32_t dict_offset,
|
|
163164
|
+
uint16_t string_len) {
|
|
163165
|
+
D_ASSERT(dict_offset >= 0 && dict_offset <= Storage::BLOCK_SIZE);
|
|
163166
|
+
|
|
163167
|
+
if (dict_offset == 0) {
|
|
163168
|
+
return string_t(nullptr, 0);
|
|
163169
|
+
}
|
|
163170
|
+
// normal string: read string from this block
|
|
163171
|
+
auto dict_end = baseptr + dict.end;
|
|
163172
|
+
auto dict_pos = dict_end - dict_offset;
|
|
163173
|
+
|
|
163174
|
+
auto str_ptr = (char *)(dict_pos);
|
|
163175
|
+
return string_t(str_ptr, string_len);
|
|
163176
|
+
}
|
|
163177
|
+
|
|
163178
|
+
uint16_t DictionaryCompressionStorage::GetStringLength(uint32_t *index_buffer_ptr, sel_t index) {
|
|
163179
|
+
if (index == 0) {
|
|
163180
|
+
return 0;
|
|
163181
|
+
} else {
|
|
163182
|
+
return index_buffer_ptr[index] - index_buffer_ptr[index - 1];
|
|
163183
|
+
}
|
|
163184
|
+
}
|
|
163185
|
+
|
|
163186
|
+
//===--------------------------------------------------------------------===//
|
|
163187
|
+
// Get Function
|
|
163188
|
+
//===--------------------------------------------------------------------===//
|
|
163189
|
+
CompressionFunction DictionaryCompressionFun::GetFunction(PhysicalType data_type) {
|
|
163190
|
+
return CompressionFunction(
|
|
163191
|
+
CompressionType::COMPRESSION_DICTIONARY, data_type, DictionaryCompressionStorage ::StringInitAnalyze,
|
|
163192
|
+
DictionaryCompressionStorage::StringAnalyze, DictionaryCompressionStorage::StringFinalAnalyze,
|
|
163193
|
+
DictionaryCompressionStorage::InitCompression, DictionaryCompressionStorage::Compress,
|
|
163194
|
+
DictionaryCompressionStorage::FinalizeCompress, DictionaryCompressionStorage::StringInitScan,
|
|
163195
|
+
DictionaryCompressionStorage::StringScan, DictionaryCompressionStorage::StringScanPartial<false>,
|
|
163196
|
+
DictionaryCompressionStorage::StringFetchRow, UncompressedFunctions::EmptySkip);
|
|
163197
|
+
}
|
|
163198
|
+
|
|
163199
|
+
bool DictionaryCompressionFun::TypeIsSupported(PhysicalType type) {
|
|
163200
|
+
return type == PhysicalType::VARCHAR;
|
|
163201
|
+
}
|
|
163202
|
+
} // namespace duckdb
|
|
163203
|
+
|
|
163204
|
+
|
|
163205
|
+
|
|
163206
|
+
|
|
163207
|
+
|
|
163208
|
+
|
|
163209
|
+
|
|
163210
|
+
|
|
163211
|
+
|
|
163212
|
+
|
|
163213
|
+
|
|
162244
163214
|
namespace duckdb {
|
|
162245
163215
|
|
|
162246
163216
|
//===--------------------------------------------------------------------===//
|
|
@@ -162272,35 +163242,31 @@ idx_t FixedSizeFinalAnalyze(AnalyzeState &state_p) {
|
|
|
162272
163242
|
//===--------------------------------------------------------------------===//
|
|
162273
163243
|
// Compress
|
|
162274
163244
|
//===--------------------------------------------------------------------===//
|
|
162275
|
-
|
|
162276
|
-
|
|
162277
|
-
|
|
162278
|
-
|
|
162279
|
-
|
|
162280
|
-
void CreateEmptySegment(idx_t row_start) {
|
|
162281
|
-
auto &db = checkpointer.GetDatabase();
|
|
162282
|
-
auto &type = checkpointer.GetType();
|
|
162283
|
-
auto compressed_segment = ColumnSegment::CreateTransientSegment(db, type, row_start);
|
|
162284
|
-
if (type.InternalType() == PhysicalType::VARCHAR) {
|
|
162285
|
-
auto &state = (UncompressedStringSegmentState &)*compressed_segment->GetSegmentState();
|
|
162286
|
-
state.overflow_writer = make_unique<WriteOverflowStringsToDisk>(db);
|
|
162287
|
-
}
|
|
162288
|
-
current_segment = move(compressed_segment);
|
|
162289
|
-
}
|
|
163245
|
+
UncompressedCompressState::UncompressedCompressState(ColumnDataCheckpointer &checkpointer)
|
|
163246
|
+
: checkpointer(checkpointer) {
|
|
163247
|
+
CreateEmptySegment(checkpointer.GetRowGroup().start);
|
|
163248
|
+
}
|
|
162290
163249
|
|
|
162291
|
-
|
|
162292
|
-
|
|
162293
|
-
|
|
163250
|
+
void UncompressedCompressState::CreateEmptySegment(idx_t row_start) {
|
|
163251
|
+
auto &db = checkpointer.GetDatabase();
|
|
163252
|
+
auto &type = checkpointer.GetType();
|
|
163253
|
+
auto compressed_segment = ColumnSegment::CreateTransientSegment(db, type, row_start);
|
|
163254
|
+
if (type.InternalType() == PhysicalType::VARCHAR) {
|
|
163255
|
+
auto &state = (UncompressedStringSegmentState &)*compressed_segment->GetSegmentState();
|
|
163256
|
+
state.overflow_writer = make_unique<WriteOverflowStringsToDisk>(db);
|
|
162294
163257
|
}
|
|
163258
|
+
current_segment = move(compressed_segment);
|
|
163259
|
+
}
|
|
162295
163260
|
|
|
162296
|
-
|
|
162297
|
-
|
|
162298
|
-
|
|
162299
|
-
|
|
163261
|
+
void UncompressedCompressState::FlushSegment(idx_t segment_size) {
|
|
163262
|
+
auto &state = checkpointer.GetCheckpointState();
|
|
163263
|
+
state.FlushSegment(move(current_segment), segment_size);
|
|
163264
|
+
}
|
|
162300
163265
|
|
|
162301
|
-
|
|
162302
|
-
|
|
162303
|
-
|
|
163266
|
+
void UncompressedCompressState::Finalize(idx_t segment_size) {
|
|
163267
|
+
FlushSegment(segment_size);
|
|
163268
|
+
current_segment.reset();
|
|
163269
|
+
}
|
|
162304
163270
|
|
|
162305
163271
|
unique_ptr<CompressionState> UncompressedFunctions::InitCompression(ColumnDataCheckpointer &checkpointer,
|
|
162306
163272
|
unique_ptr<AnalyzeState> state) {
|
|
@@ -163059,17 +164025,6 @@ bool RLEFun::TypeIsSupported(PhysicalType type) {
|
|
|
163059
164025
|
} // namespace duckdb
|
|
163060
164026
|
|
|
163061
164027
|
|
|
163062
|
-
|
|
163063
|
-
|
|
163064
|
-
|
|
163065
|
-
|
|
163066
|
-
|
|
163067
|
-
|
|
163068
|
-
|
|
163069
|
-
|
|
163070
|
-
|
|
163071
|
-
|
|
163072
|
-
|
|
163073
164028
|
namespace duckdb {
|
|
163074
164029
|
|
|
163075
164030
|
//===--------------------------------------------------------------------===//
|
|
@@ -163082,70 +164037,6 @@ UncompressedStringSegmentState::~UncompressedStringSegmentState() {
|
|
|
163082
164037
|
}
|
|
163083
164038
|
}
|
|
163084
164039
|
|
|
163085
|
-
struct StringDictionaryContainer {
|
|
163086
|
-
//! The size of the dictionary
|
|
163087
|
-
uint32_t size;
|
|
163088
|
-
//! The end of the dictionary (typically Storage::BLOCK_SIZE)
|
|
163089
|
-
uint32_t end;
|
|
163090
|
-
|
|
163091
|
-
void Verify() {
|
|
163092
|
-
D_ASSERT(size <= Storage::BLOCK_SIZE);
|
|
163093
|
-
D_ASSERT(end <= Storage::BLOCK_SIZE);
|
|
163094
|
-
D_ASSERT(size <= end);
|
|
163095
|
-
}
|
|
163096
|
-
};
|
|
163097
|
-
|
|
163098
|
-
struct UncompressedStringStorage {
|
|
163099
|
-
public:
|
|
163100
|
-
//! Dictionary header size at the beginning of the string segment (offset + length)
|
|
163101
|
-
static constexpr uint16_t DICTIONARY_HEADER_SIZE = sizeof(uint32_t) + sizeof(uint32_t);
|
|
163102
|
-
//! Marker used in length field to indicate the presence of a big string
|
|
163103
|
-
static constexpr uint16_t BIG_STRING_MARKER = (uint16_t)-1;
|
|
163104
|
-
//! Base size of big string marker (block id + offset)
|
|
163105
|
-
static constexpr idx_t BIG_STRING_MARKER_BASE_SIZE = sizeof(block_id_t) + sizeof(int32_t);
|
|
163106
|
-
//! The marker size of the big string
|
|
163107
|
-
static constexpr idx_t BIG_STRING_MARKER_SIZE = BIG_STRING_MARKER_BASE_SIZE + sizeof(uint16_t);
|
|
163108
|
-
|
|
163109
|
-
public:
|
|
163110
|
-
static unique_ptr<AnalyzeState> StringInitAnalyze(ColumnData &col_data, PhysicalType type);
|
|
163111
|
-
static bool StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count);
|
|
163112
|
-
static idx_t StringFinalAnalyze(AnalyzeState &state_p);
|
|
163113
|
-
static unique_ptr<SegmentScanState> StringInitScan(ColumnSegment &segment);
|
|
163114
|
-
static void StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result,
|
|
163115
|
-
idx_t result_offset);
|
|
163116
|
-
static void StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result);
|
|
163117
|
-
static void StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result,
|
|
163118
|
-
idx_t result_idx);
|
|
163119
|
-
static unique_ptr<CompressedSegmentState> StringInitSegment(ColumnSegment &segment, block_id_t block_id);
|
|
163120
|
-
static idx_t StringAppend(ColumnSegment &segment, SegmentStatistics &stats, VectorData &data, idx_t offset,
|
|
163121
|
-
idx_t count);
|
|
163122
|
-
static idx_t FinalizeAppend(ColumnSegment &segment, SegmentStatistics &stats);
|
|
163123
|
-
|
|
163124
|
-
public:
|
|
163125
|
-
static inline void UpdateStringStats(SegmentStatistics &stats, const string_t &new_value) {
|
|
163126
|
-
auto &sstats = (StringStatistics &)*stats.statistics;
|
|
163127
|
-
sstats.Update(new_value);
|
|
163128
|
-
}
|
|
163129
|
-
|
|
163130
|
-
static void SetDictionary(ColumnSegment &segment, BufferHandle &handle, StringDictionaryContainer dict);
|
|
163131
|
-
static StringDictionaryContainer GetDictionary(ColumnSegment &segment, BufferHandle &handle);
|
|
163132
|
-
static idx_t RemainingSpace(ColumnSegment &segment, BufferHandle &handle);
|
|
163133
|
-
static void WriteString(ColumnSegment &segment, string_t string, block_id_t &result_block, int32_t &result_offset);
|
|
163134
|
-
static void WriteStringMemory(ColumnSegment &segment, string_t string, block_id_t &result_block,
|
|
163135
|
-
int32_t &result_offset);
|
|
163136
|
-
static string_t ReadString(ColumnSegment &segment, Vector &result, block_id_t block, int32_t offset);
|
|
163137
|
-
static string_t ReadString(data_ptr_t target, int32_t offset);
|
|
163138
|
-
static void WriteStringMarker(data_ptr_t target, block_id_t block_id, int32_t offset);
|
|
163139
|
-
static void ReadStringMarker(data_ptr_t target, block_id_t &block_id, int32_t &offset);
|
|
163140
|
-
|
|
163141
|
-
static string_location_t FetchStringLocation(StringDictionaryContainer dict, data_ptr_t baseptr,
|
|
163142
|
-
int32_t dict_offset);
|
|
163143
|
-
static string_t FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result,
|
|
163144
|
-
data_ptr_t baseptr, int32_t dict_offset);
|
|
163145
|
-
static string_t FetchString(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result,
|
|
163146
|
-
data_ptr_t baseptr, string_location_t location);
|
|
163147
|
-
};
|
|
163148
|
-
|
|
163149
164040
|
//===--------------------------------------------------------------------===//
|
|
163150
164041
|
// Analyze
|
|
163151
164042
|
//===--------------------------------------------------------------------===//
|
|
@@ -163190,10 +164081,6 @@ idx_t UncompressedStringStorage::StringFinalAnalyze(AnalyzeState &state_p) {
|
|
|
163190
164081
|
//===--------------------------------------------------------------------===//
|
|
163191
164082
|
// Scan
|
|
163192
164083
|
//===--------------------------------------------------------------------===//
|
|
163193
|
-
struct StringScanState : public SegmentScanState {
|
|
163194
|
-
unique_ptr<BufferHandle> handle;
|
|
163195
|
-
};
|
|
163196
|
-
|
|
163197
164084
|
unique_ptr<SegmentScanState> UncompressedStringStorage::StringInitScan(ColumnSegment &segment) {
|
|
163198
164085
|
auto result = make_unique<StringScanState>();
|
|
163199
164086
|
auto &buffer_manager = BufferManager::GetBufferManager(segment.db);
|
|
@@ -163270,82 +164157,6 @@ unique_ptr<CompressedSegmentState> UncompressedStringStorage::StringInitSegment(
|
|
|
163270
164157
|
return make_unique<UncompressedStringSegmentState>();
|
|
163271
164158
|
}
|
|
163272
164159
|
|
|
163273
|
-
idx_t UncompressedStringStorage::StringAppend(ColumnSegment &segment, SegmentStatistics &stats, VectorData &data,
|
|
163274
|
-
idx_t offset, idx_t count) {
|
|
163275
|
-
auto &buffer_manager = BufferManager::GetBufferManager(segment.db);
|
|
163276
|
-
auto handle = buffer_manager.Pin(segment.block);
|
|
163277
|
-
|
|
163278
|
-
D_ASSERT(segment.GetBlockOffset() == 0);
|
|
163279
|
-
auto source_data = (string_t *)data.data;
|
|
163280
|
-
auto result_data = (int32_t *)(handle->node->buffer + DICTIONARY_HEADER_SIZE);
|
|
163281
|
-
for (idx_t i = 0; i < count; i++) {
|
|
163282
|
-
auto source_idx = data.sel->get_index(offset + i);
|
|
163283
|
-
auto target_idx = segment.count.load();
|
|
163284
|
-
idx_t remaining_space = RemainingSpace(segment, *handle);
|
|
163285
|
-
if (remaining_space < sizeof(int32_t)) {
|
|
163286
|
-
// string index does not fit in the block at all
|
|
163287
|
-
return i;
|
|
163288
|
-
}
|
|
163289
|
-
remaining_space -= sizeof(int32_t);
|
|
163290
|
-
if (!data.validity.RowIsValid(source_idx)) {
|
|
163291
|
-
// null value is stored as -1
|
|
163292
|
-
result_data[target_idx] = 0;
|
|
163293
|
-
} else {
|
|
163294
|
-
auto dictionary = GetDictionary(segment, *handle);
|
|
163295
|
-
auto end = handle->node->buffer + dictionary.end;
|
|
163296
|
-
|
|
163297
|
-
dictionary.Verify();
|
|
163298
|
-
// non-null value, check if we can fit it within the block
|
|
163299
|
-
idx_t string_length = source_data[source_idx].GetSize();
|
|
163300
|
-
idx_t dictionary_length = string_length + sizeof(uint16_t);
|
|
163301
|
-
|
|
163302
|
-
// determine whether or not we have space in the block for this string
|
|
163303
|
-
bool use_overflow_block = false;
|
|
163304
|
-
idx_t required_space = dictionary_length;
|
|
163305
|
-
if (required_space >= StringUncompressed::STRING_BLOCK_LIMIT) {
|
|
163306
|
-
// string exceeds block limit, store in overflow block and only write a marker here
|
|
163307
|
-
required_space = BIG_STRING_MARKER_SIZE;
|
|
163308
|
-
use_overflow_block = true;
|
|
163309
|
-
}
|
|
163310
|
-
if (required_space > remaining_space) {
|
|
163311
|
-
// no space remaining: return how many tuples we ended up writing
|
|
163312
|
-
return i;
|
|
163313
|
-
}
|
|
163314
|
-
// we have space: write the string
|
|
163315
|
-
UpdateStringStats(stats, source_data[source_idx]);
|
|
163316
|
-
|
|
163317
|
-
if (use_overflow_block) {
|
|
163318
|
-
// write to overflow blocks
|
|
163319
|
-
block_id_t block;
|
|
163320
|
-
int32_t offset;
|
|
163321
|
-
// write the string into the current string block
|
|
163322
|
-
WriteString(segment, source_data[source_idx], block, offset);
|
|
163323
|
-
dictionary.size += BIG_STRING_MARKER_SIZE;
|
|
163324
|
-
auto dict_pos = end - dictionary.size;
|
|
163325
|
-
|
|
163326
|
-
// write a big string marker into the dictionary
|
|
163327
|
-
WriteStringMarker(dict_pos, block, offset);
|
|
163328
|
-
} else {
|
|
163329
|
-
// string fits in block, append to dictionary and increment dictionary position
|
|
163330
|
-
D_ASSERT(string_length < NumericLimits<uint16_t>::Maximum());
|
|
163331
|
-
dictionary.size += required_space;
|
|
163332
|
-
auto dict_pos = end - dictionary.size; // first write the length as u16
|
|
163333
|
-
Store<uint16_t>(string_length, dict_pos);
|
|
163334
|
-
// now write the actual string data into the dictionary
|
|
163335
|
-
memcpy(dict_pos + sizeof(uint16_t), source_data[source_idx].GetDataUnsafe(), string_length);
|
|
163336
|
-
}
|
|
163337
|
-
D_ASSERT(RemainingSpace(segment, *handle) <= Storage::BLOCK_SIZE);
|
|
163338
|
-
// place the dictionary offset into the set of vectors
|
|
163339
|
-
dictionary.Verify();
|
|
163340
|
-
|
|
163341
|
-
result_data[target_idx] = dictionary.size;
|
|
163342
|
-
SetDictionary(segment, *handle, dictionary);
|
|
163343
|
-
}
|
|
163344
|
-
segment.count++;
|
|
163345
|
-
}
|
|
163346
|
-
return count;
|
|
163347
|
-
}
|
|
163348
|
-
|
|
163349
164160
|
idx_t UncompressedStringStorage::FinalizeAppend(ColumnSegment &segment, SegmentStatistics &stats) {
|
|
163350
164161
|
auto &buffer_manager = BufferManager::GetBufferManager(segment.db);
|
|
163351
164162
|
auto handle = buffer_manager.Pin(segment.block);
|
|
@@ -163354,7 +164165,7 @@ idx_t UncompressedStringStorage::FinalizeAppend(ColumnSegment &segment, SegmentS
|
|
|
163354
164165
|
// compute the total size required to store this segment
|
|
163355
164166
|
auto offset_size = DICTIONARY_HEADER_SIZE + segment.count * sizeof(int32_t);
|
|
163356
164167
|
auto total_size = offset_size + dict.size;
|
|
163357
|
-
if (total_size >=
|
|
164168
|
+
if (total_size >= COMPACTION_FLUSH_LIMIT) {
|
|
163358
164169
|
// the block is full enough, don't bother moving around the dictionary
|
|
163359
164170
|
return Storage::BLOCK_SIZE;
|
|
163360
164171
|
}
|