duckdb 0.3.3-dev581.0 → 0.3.3-dev626.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/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
- // Jenkins hash function: https://en.wikipedia.org/wiki/Jenkins_hash_function
34011
- uint32_t JenkinsOneAtATimeHash(const char *key, size_t length) {
34012
- size_t i = 0;
34013
- uint32_t hash = 0;
34014
- while (i != length) {
34015
- hash += key[i++];
34016
- hash += hash << 10;
34017
- hash ^= hash >> 6;
34018
- }
34019
- hash += hash << 3;
34020
- hash ^= hash >> 11;
34021
- hash += hash << 15;
34022
- return hash;
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
- auto hash_val = JenkinsOneAtATimeHash(val, size);
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 Hash((const char *)val, size);
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
- //! Scans a base vector from the column
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 ColumnDataCheckpointer {
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
- DatabaseInstance &GetDatabase();
161531
- const LogicalType &GetType() const;
161532
- ColumnData &GetColumnData();
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
- #include <functional>
161400
+ if (misaligned_count) {
161401
+ count -= misaligned_count;
161402
+ }
161561
161403
 
161562
- namespace duckdb {
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
- using bitpacking_width_t = uint8_t;
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
- // Note that optimizations in scanning only work if this value is equal to STANDARD_VECTOR_SIZE, however we keep them
161567
- // separated to prevent the code from break on lower vector sizes
161568
- static constexpr const idx_t BITPACKING_WIDTH_GROUP_SIZE = 1024;
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
- class BitpackingPrimitives {
161571
- public:
161572
- static constexpr const idx_t BITPACKING_ALGORITHM_GROUP_SIZE = 32;
161573
- static constexpr const idx_t BITPACKING_HEADER_SIZE = sizeof(uint64_t);
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 bitpacking_width_t MinimumBitWidth(T min_value, T max_value) {
161598
- bitpacking_width_t required_bits;
161599
-
161600
- if (std::is_signed<T>::value) {
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
- while (max_value) {
161620
- required_bits++;
161621
- max_value >>= 1;
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 GetEffectiveWidth<T>(required_bits);
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
- bitpacking_width_t calc_width = MinimumBitWidth<T>(std::is_signed<T>::value ? min_value : 0, max_value);
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 (calc_width < sizeof(T) * 8 && calc_width != 0) {
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 << (calc_width - 1)) - 1);
161651
- D_ASSERT((int64_t)min_value >= (int64_t)(-1 * ((1L << (calc_width - 1)) - 1) - 1));
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 << (calc_width)) - 1);
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 (calc_width / 8 + (calc_width % 8 != 0)) * 8;
161534
+ return (bitwidth / 8 + (bitwidth % 8 != 0)) * 8;
161659
161535
  } else {
161660
- return calc_width;
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
- idx_t compress_loops = BITPACKING_WIDTH_GROUP_SIZE / BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE;
161895
- for (idx_t i = 0; i < compress_loops; i++) {
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
- struct UncompressedCompressState : public CompressionState {
162276
- explicit UncompressedCompressState(ColumnDataCheckpointer &checkpointer) : checkpointer(checkpointer) {
162277
- CreateEmptySegment(checkpointer.GetRowGroup().start);
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
- void FlushSegment(idx_t segment_size) {
162292
- auto &state = checkpointer.GetCheckpointState();
162293
- state.FlushSegment(move(current_segment), segment_size);
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
- void Finalize(idx_t segment_size) {
162297
- FlushSegment(segment_size);
162298
- current_segment.reset();
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
- ColumnDataCheckpointer &checkpointer;
162302
- unique_ptr<ColumnSegment> current_segment;
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 >= Storage::BLOCK_SIZE / 5 * 4) {
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
  }