@nxtedition/rocksdb 15.1.2 → 15.1.4
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/.claude/settings.local.json +15 -0
- package/binding.cc +79 -38
- package/build.sh +1 -2
- package/deps/rocksdb/rocksdb/BUCK +10 -8
- package/deps/rocksdb/rocksdb/CMakeLists.txt +27 -2
- package/deps/rocksdb/rocksdb/Makefile +27 -116
- package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +1 -1
- package/deps/rocksdb/rocksdb/cache/clock_cache.cc +101 -124
- package/deps/rocksdb/rocksdb/cache/clock_cache.h +47 -30
- package/deps/rocksdb/rocksdb/db/c.cc +793 -131
- package/deps/rocksdb/rocksdb/db/c_test.c +571 -0
- package/deps/rocksdb/rocksdb/db/compact_files_test.cc +226 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction.h +4 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +95 -59
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +2 -2
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +45 -35
- package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.cc +8 -4
- package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.h +1 -1
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.cc +11 -6
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker.h +8 -2
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +47 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +12 -2
- package/deps/rocksdb/rocksdb/db/compaction/compaction_service_test.cc +82 -0
- package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.cc +2 -2
- package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.h +1 -1
- package/deps/rocksdb/rocksdb/db/db_basic_test.cc +69 -24
- package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +9 -1
- package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +65 -0
- package/deps/rocksdb/rocksdb/db/db_etc3_test.cc +161 -0
- package/deps/rocksdb/rocksdb/db/db_filesnapshot.cc +1 -0
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +20 -7
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +13 -0
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +114 -39
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +3 -0
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_follower.cc +3 -3
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +1 -1
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_secondary.cc +39 -25
- package/deps/rocksdb/rocksdb/db/db_iterator_test.cc +361 -0
- package/deps/rocksdb/rocksdb/db/db_options_test.cc +35 -0
- package/deps/rocksdb/rocksdb/db/db_range_del_test.cc +83 -0
- package/deps/rocksdb/rocksdb/db/db_test.cc +249 -4
- package/deps/rocksdb/rocksdb/db/db_test2.cc +3 -0
- package/deps/rocksdb/rocksdb/db/db_test_util.cc +2 -1
- package/deps/rocksdb/rocksdb/db/db_wal_test.cc +3 -2
- package/deps/rocksdb/rocksdb/db/flush_job_test.cc +7 -7
- package/deps/rocksdb/rocksdb/db/listener_test.cc +7 -17
- package/deps/rocksdb/rocksdb/db/memtable_list_test.cc +4 -2
- package/deps/rocksdb/rocksdb/db/obsolete_files_test.cc +41 -0
- package/deps/rocksdb/rocksdb/db/repair.cc +2 -2
- package/deps/rocksdb/rocksdb/db/version_edit.h +7 -4
- package/deps/rocksdb/rocksdb/db/version_set.cc +299 -90
- package/deps/rocksdb/rocksdb/db/version_set.h +56 -9
- package/deps/rocksdb/rocksdb/db/version_set_test.cc +41 -39
- package/deps/rocksdb/rocksdb/db/version_util.h +3 -2
- package/deps/rocksdb/rocksdb/db/wal_manager.cc +7 -1
- package/deps/rocksdb/rocksdb/db/wal_manager_test.cc +48 -10
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +1 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +5 -1
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +16 -5
- package/deps/rocksdb/rocksdb/env/env_test.cc +126 -41
- package/deps/rocksdb/rocksdb/env/fs_posix.cc +14 -7
- package/deps/rocksdb/rocksdb/env/io_posix.cc +304 -112
- package/deps/rocksdb/rocksdb/env/io_posix.h +16 -4
- package/deps/rocksdb/rocksdb/env/io_posix_test.cc +43 -0
- package/deps/rocksdb/rocksdb/folly.mk +148 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/advanced_compression.h +29 -3
- package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +73 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/c.h +246 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/compaction_filter.h +0 -2
- package/deps/rocksdb/rocksdb/include/rocksdb/data_structure.h +15 -9
- package/deps/rocksdb/rocksdb/include/rocksdb/db.h +19 -9
- package/deps/rocksdb/rocksdb/include/rocksdb/env.h +1 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/file_system.h +6 -4
- package/deps/rocksdb/rocksdb/include/rocksdb/metadata.h +14 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/options.h +67 -6
- package/deps/rocksdb/rocksdb/include/rocksdb/sst_file_writer.h +1 -7
- package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +3 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/thread_status.h +6 -14
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/backup_engine.h +8 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/env_mirror.h +2 -2
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/ldb_cmd_execute_result.h +0 -4
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/option_change_migration.h +33 -5
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/stackable_db.h +6 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/version.h +2 -2
- package/deps/rocksdb/rocksdb/monitoring/statistics.cc +2 -0
- package/deps/rocksdb/rocksdb/monitoring/thread_status_impl.cc +5 -2
- package/deps/rocksdb/rocksdb/monitoring/thread_status_updater.cc +2 -2
- package/deps/rocksdb/rocksdb/monitoring/thread_status_updater.h +6 -6
- package/deps/rocksdb/rocksdb/monitoring/thread_status_updater_debug.cc +2 -2
- package/deps/rocksdb/rocksdb/monitoring/thread_status_util.cc +10 -5
- package/deps/rocksdb/rocksdb/monitoring/thread_status_util.h +2 -2
- package/deps/rocksdb/rocksdb/options/cf_options.cc +15 -3
- package/deps/rocksdb/rocksdb/options/cf_options.h +7 -0
- package/deps/rocksdb/rocksdb/options/db_options.cc +27 -36
- package/deps/rocksdb/rocksdb/options/db_options.h +3 -2
- package/deps/rocksdb/rocksdb/options/options.cc +4 -0
- package/deps/rocksdb/rocksdb/options/options_helper.cc +8 -2
- package/deps/rocksdb/rocksdb/options/options_settable_test.cc +4 -1
- package/deps/rocksdb/rocksdb/options/options_test.cc +19 -3
- package/deps/rocksdb/rocksdb/src.mk +1 -1
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +155 -32
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.h +7 -3
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.cc +169 -125
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.h +22 -7
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +43 -24
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +9 -5
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_test.cc +9 -8
- package/deps/rocksdb/rocksdb/table/block_based/filter_block.h +17 -0
- package/deps/rocksdb/rocksdb/table/block_based/filter_policy.cc +15 -5
- package/deps/rocksdb/rocksdb/table/block_based/filter_policy_internal.h +13 -18
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.cc +29 -0
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.h +6 -0
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block_test.cc +15 -0
- package/deps/rocksdb/rocksdb/table/block_based/index_builder.cc +79 -19
- package/deps/rocksdb/rocksdb/table/block_based/index_builder.h +48 -20
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +51 -0
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.h +19 -0
- package/deps/rocksdb/rocksdb/table/block_based/user_defined_index_wrapper.h +1 -1
- package/deps/rocksdb/rocksdb/table/external_table.cc +2 -2
- package/deps/rocksdb/rocksdb/table/sst_file_dumper.cc +3 -2
- package/deps/rocksdb/rocksdb/table/sst_file_dumper.h +3 -1
- package/deps/rocksdb/rocksdb/table/table_builder.h +5 -0
- package/deps/rocksdb/rocksdb/table/table_reader.h +4 -2
- package/deps/rocksdb/rocksdb/table/table_test.cc +48 -39
- package/deps/rocksdb/rocksdb/test_util/sync_point.cc +4 -0
- package/deps/rocksdb/rocksdb/test_util/sync_point.h +32 -0
- package/deps/rocksdb/rocksdb/test_util/testutil.h +6 -2
- package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +14 -4
- package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +8 -5
- package/deps/rocksdb/rocksdb/tools/ldb_cmd_test.cc +3 -2
- package/deps/rocksdb/rocksdb/tools/sst_dump_tool.cc +63 -12
- package/deps/rocksdb/rocksdb/util/auto_tune_compressor.cc +16 -1
- package/deps/rocksdb/rocksdb/util/auto_tune_compressor.h +5 -1
- package/deps/rocksdb/rocksdb/util/bit_fields.h +133 -23
- package/deps/rocksdb/rocksdb/util/bloom_test.cc +2 -5
- package/deps/rocksdb/rocksdb/util/compression.cc +51 -23
- package/deps/rocksdb/rocksdb/util/compression_test.cc +525 -270
- package/deps/rocksdb/rocksdb/util/filter_bench.cc +3 -4
- package/deps/rocksdb/rocksdb/util/simple_mixed_compressor.cc +11 -2
- package/deps/rocksdb/rocksdb/util/simple_mixed_compressor.h +4 -1
- package/deps/rocksdb/rocksdb/util/slice_test.cc +92 -0
- package/deps/rocksdb/rocksdb/util/thread_list_test.cc +2 -2
- package/deps/rocksdb/rocksdb/util/thread_operation.h +2 -2
- package/deps/rocksdb/rocksdb/util/threadpool_imp.cc +2 -2
- package/deps/rocksdb/rocksdb/utilities/backup/backup_engine.cc +19 -2
- package/deps/rocksdb/rocksdb/utilities/backup/backup_engine_test.cc +75 -0
- package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_test.cc +1 -0
- package/deps/rocksdb/rocksdb/utilities/option_change_migration/option_change_migration.cc +303 -111
- package/deps/rocksdb/rocksdb/utilities/option_change_migration/option_change_migration_test.cc +379 -0
- package/deps/rocksdb/rocksdb.gyp +1 -0
- package/iterator.js +66 -70
- package/package.json +6 -6
- package/prebuilds/darwin-arm64/@nxtedition+rocksdb.node +0 -0
- package/deps/rocksdb/rocksdb/table/block_based/index_builder_test.cc +0 -183
|
@@ -1752,26 +1752,6 @@ inline void GetHomeIndexAndShift(uint64_t length_info, uint64_t hash,
|
|
|
1752
1752
|
assert(*home < LengthInfoToUsedLength(length_info));
|
|
1753
1753
|
}
|
|
1754
1754
|
|
|
1755
|
-
inline int GetShiftFromNextWithShift(uint64_t next_with_shift) {
|
|
1756
|
-
return BitwiseAnd(next_with_shift,
|
|
1757
|
-
AutoHyperClockTable::HandleImpl::kShiftMask);
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
inline size_t GetNextFromNextWithShift(uint64_t next_with_shift) {
|
|
1761
|
-
return static_cast<size_t>(next_with_shift >>
|
|
1762
|
-
AutoHyperClockTable::HandleImpl::kNextShift);
|
|
1763
|
-
}
|
|
1764
|
-
|
|
1765
|
-
inline uint64_t MakeNextWithShift(size_t next, int shift) {
|
|
1766
|
-
return (uint64_t{next} << AutoHyperClockTable::HandleImpl::kNextShift) |
|
|
1767
|
-
static_cast<uint64_t>(shift);
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
|
-
inline uint64_t MakeNextWithShiftEnd(size_t head, int shift) {
|
|
1771
|
-
return AutoHyperClockTable::HandleImpl::kNextEndFlags |
|
|
1772
|
-
MakeNextWithShift(head, shift);
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
1755
|
// Helper function for Lookup
|
|
1776
1756
|
inline bool MatchAndRef(const UniqueId64x2* hashed_key, const ClockHandle& h,
|
|
1777
1757
|
int shift = 0, size_t home = 0,
|
|
@@ -1821,36 +1801,39 @@ inline bool MatchAndRef(const UniqueId64x2* hashed_key, const ClockHandle& h,
|
|
|
1821
1801
|
}
|
|
1822
1802
|
}
|
|
1823
1803
|
|
|
1804
|
+
using NextWithShift = AutoHyperClockTable::HandleImpl::NextWithShift;
|
|
1805
|
+
|
|
1824
1806
|
// Assumes a chain rewrite lock prevents concurrent modification of
|
|
1825
1807
|
// these chain pointers
|
|
1826
1808
|
void UpgradeShiftsOnRange(AutoHyperClockTable::HandleImpl* arr,
|
|
1827
|
-
size_t& frontier,
|
|
1828
|
-
|
|
1809
|
+
size_t& frontier,
|
|
1810
|
+
NextWithShift stop_before_or_new_tail, int old_shift,
|
|
1811
|
+
int new_shift) {
|
|
1829
1812
|
assert(frontier != SIZE_MAX);
|
|
1830
1813
|
assert(new_shift == old_shift + 1);
|
|
1831
1814
|
(void)old_shift;
|
|
1832
1815
|
(void)new_shift;
|
|
1833
|
-
using HandleImpl = AutoHyperClockTable::HandleImpl;
|
|
1834
1816
|
for (;;) {
|
|
1835
|
-
|
|
1836
|
-
assert(
|
|
1817
|
+
NextWithShift next_with_shift = arr[frontier].chain_next_with_shift.Load();
|
|
1818
|
+
assert(next_with_shift.GetShift() == old_shift);
|
|
1837
1819
|
if (next_with_shift == stop_before_or_new_tail) {
|
|
1838
1820
|
// Stopping at entry with pointer matching "stop before"
|
|
1839
|
-
assert(!
|
|
1821
|
+
assert(!next_with_shift.IsEnd());
|
|
1840
1822
|
return;
|
|
1841
1823
|
}
|
|
1842
|
-
if (
|
|
1824
|
+
if (next_with_shift.IsEnd()) {
|
|
1843
1825
|
// Also update tail to new tail
|
|
1844
|
-
assert(
|
|
1826
|
+
assert(stop_before_or_new_tail.IsEnd());
|
|
1845
1827
|
arr[frontier].chain_next_with_shift.Store(stop_before_or_new_tail);
|
|
1846
1828
|
// Mark nothing left to upgrade
|
|
1847
1829
|
frontier = SIZE_MAX;
|
|
1848
1830
|
return;
|
|
1849
1831
|
}
|
|
1850
1832
|
// Next is another entry to process, so upgrade and advance frontier
|
|
1851
|
-
arr[frontier].chain_next_with_shift.
|
|
1852
|
-
|
|
1853
|
-
|
|
1833
|
+
arr[frontier].chain_next_with_shift.Apply(
|
|
1834
|
+
NextWithShift::Shift::PlusTransformPromiseNoOverflow(1U));
|
|
1835
|
+
assert(next_with_shift.GetShift() + 1 == new_shift);
|
|
1836
|
+
frontier = next_with_shift.GetNext();
|
|
1854
1837
|
}
|
|
1855
1838
|
}
|
|
1856
1839
|
|
|
@@ -1888,19 +1871,19 @@ class AutoHyperClockTable::ChainRewriteLock {
|
|
|
1888
1871
|
// RAII wrap existing lock held (or end)
|
|
1889
1872
|
explicit ChainRewriteLock(HandleImpl* h,
|
|
1890
1873
|
RelaxedAtomic<uint64_t>& /*yield_count*/,
|
|
1891
|
-
|
|
1874
|
+
NextWithShift already_locked_or_end)
|
|
1892
1875
|
: head_ptr_(&h->head_next_with_shift) {
|
|
1893
1876
|
saved_head_ = already_locked_or_end;
|
|
1894
1877
|
// already locked or end
|
|
1895
|
-
assert(saved_head_
|
|
1878
|
+
assert(saved_head_.IsLocked());
|
|
1896
1879
|
}
|
|
1897
1880
|
|
|
1898
1881
|
~ChainRewriteLock() {
|
|
1899
1882
|
if (!IsEnd()) {
|
|
1900
1883
|
// Release lock
|
|
1901
|
-
|
|
1902
|
-
(
|
|
1903
|
-
assert((
|
|
1884
|
+
NextWithShift old;
|
|
1885
|
+
head_ptr_->Apply(NextWithShift::LockedFlag::ClearTransform(), &old);
|
|
1886
|
+
assert(old.IsLockedNotEnd());
|
|
1904
1887
|
}
|
|
1905
1888
|
}
|
|
1906
1889
|
|
|
@@ -1910,12 +1893,13 @@ class AutoHyperClockTable::ChainRewriteLock {
|
|
|
1910
1893
|
}
|
|
1911
1894
|
|
|
1912
1895
|
// Expected current state, assuming no parallel updates.
|
|
1913
|
-
|
|
1896
|
+
NextWithShift GetSavedHead() const { return saved_head_; }
|
|
1914
1897
|
|
|
1915
|
-
bool CasUpdate(
|
|
1898
|
+
bool CasUpdate(NextWithShift next_with_shift,
|
|
1916
1899
|
RelaxedAtomic<uint64_t>& yield_count) {
|
|
1917
|
-
|
|
1918
|
-
|
|
1900
|
+
NextWithShift new_head =
|
|
1901
|
+
next_with_shift.With<NextWithShift::LockedFlag>(true);
|
|
1902
|
+
NextWithShift expected = GetSavedHead();
|
|
1919
1903
|
bool success = head_ptr_->CasStrong(expected, new_head);
|
|
1920
1904
|
if (success) {
|
|
1921
1905
|
// Ensure IsEnd() is kept up-to-date, including for dtor
|
|
@@ -1924,7 +1908,7 @@ class AutoHyperClockTable::ChainRewriteLock {
|
|
|
1924
1908
|
// Parallel update to head, such as Insert()
|
|
1925
1909
|
if (IsEnd()) {
|
|
1926
1910
|
// Didn't previously hold a lock
|
|
1927
|
-
if (
|
|
1911
|
+
if (expected.IsEnd()) {
|
|
1928
1912
|
// Still don't need to
|
|
1929
1913
|
saved_head_ = expected;
|
|
1930
1914
|
} else {
|
|
@@ -1933,28 +1917,25 @@ class AutoHyperClockTable::ChainRewriteLock {
|
|
|
1933
1917
|
}
|
|
1934
1918
|
} else {
|
|
1935
1919
|
// Parallel update must preserve our lock
|
|
1936
|
-
assert((
|
|
1937
|
-
HandleImpl::kHeadLocked);
|
|
1920
|
+
assert(expected.IsLockedNotEnd());
|
|
1938
1921
|
saved_head_ = expected;
|
|
1939
1922
|
}
|
|
1940
1923
|
}
|
|
1941
1924
|
return success;
|
|
1942
1925
|
}
|
|
1943
1926
|
|
|
1944
|
-
bool IsEnd() const { return
|
|
1927
|
+
bool IsEnd() const { return saved_head_.IsEnd(); }
|
|
1945
1928
|
|
|
1946
1929
|
private:
|
|
1947
1930
|
void Acquire(RelaxedAtomic<uint64_t>& yield_count) {
|
|
1948
1931
|
for (;;) {
|
|
1949
1932
|
// Acquire removal lock on the chain
|
|
1950
|
-
|
|
1951
|
-
|
|
1933
|
+
NextWithShift old_head;
|
|
1934
|
+
head_ptr_->Apply(NextWithShift::LockedFlag::SetTransform(), &old_head,
|
|
1935
|
+
&saved_head_);
|
|
1936
|
+
if (!old_head.IsLockedNotEnd()) {
|
|
1952
1937
|
// Either acquired the lock or lock not needed (end)
|
|
1953
|
-
assert((
|
|
1954
|
-
(old_head & HandleImpl::kNextEndFlags) ==
|
|
1955
|
-
HandleImpl::kNextEndFlags);
|
|
1956
|
-
|
|
1957
|
-
saved_head_ = old_head | HandleImpl::kHeadLocked;
|
|
1938
|
+
assert(old_head.IsEnd() == old_head.IsLocked());
|
|
1958
1939
|
break;
|
|
1959
1940
|
}
|
|
1960
1941
|
// NOTE: one of the few yield-wait loops, which is rare enough in practice
|
|
@@ -1965,8 +1946,8 @@ class AutoHyperClockTable::ChainRewriteLock {
|
|
|
1965
1946
|
}
|
|
1966
1947
|
}
|
|
1967
1948
|
|
|
1968
|
-
|
|
1969
|
-
|
|
1949
|
+
AcqRelBitFieldsAtomic<NextWithShift>* head_ptr_;
|
|
1950
|
+
NextWithShift saved_head_;
|
|
1970
1951
|
};
|
|
1971
1952
|
|
|
1972
1953
|
AutoHyperClockTable::AutoHyperClockTable(
|
|
@@ -2021,9 +2002,9 @@ AutoHyperClockTable::AutoHyperClockTable(
|
|
|
2021
2002
|
#endif
|
|
2022
2003
|
if (major + i < used_length) {
|
|
2023
2004
|
array_[i].head_next_with_shift.StoreRelaxed(
|
|
2024
|
-
|
|
2005
|
+
NextWithShift::MakeEnd(i, max_shift));
|
|
2025
2006
|
array_[major + i].head_next_with_shift.StoreRelaxed(
|
|
2026
|
-
|
|
2007
|
+
NextWithShift::MakeEnd(major + i, max_shift));
|
|
2027
2008
|
#ifndef NDEBUG // Extra invariant checking
|
|
2028
2009
|
GetHomeIndexAndShift(length_info, i, &home, &shift);
|
|
2029
2010
|
assert(home == i);
|
|
@@ -2034,7 +2015,7 @@ AutoHyperClockTable::AutoHyperClockTable(
|
|
|
2034
2015
|
#endif
|
|
2035
2016
|
} else {
|
|
2036
2017
|
array_[i].head_next_with_shift.StoreRelaxed(
|
|
2037
|
-
|
|
2018
|
+
NextWithShift::MakeEnd(i, min_shift));
|
|
2038
2019
|
#ifndef NDEBUG // Extra invariant checking
|
|
2039
2020
|
GetHomeIndexAndShift(length_info, i, &home, &shift);
|
|
2040
2021
|
assert(home == i);
|
|
@@ -2066,8 +2047,10 @@ AutoHyperClockTable::~AutoHyperClockTable() {
|
|
|
2066
2047
|
// just a reasonable frontier past what we expect to have written.
|
|
2067
2048
|
#ifdef MUST_FREE_HEAP_ALLOCATIONS
|
|
2068
2049
|
for (size_t i = used_end; i < array_.Count() && i < used_end + 64U; i++) {
|
|
2069
|
-
assert(array_[i].head_next_with_shift.LoadRelaxed() ==
|
|
2070
|
-
|
|
2050
|
+
assert(array_[i].head_next_with_shift.LoadRelaxed() ==
|
|
2051
|
+
HandleImpl::kUnusedMarker);
|
|
2052
|
+
assert(array_[i].chain_next_with_shift.LoadRelaxed() ==
|
|
2053
|
+
HandleImpl::kUnusedMarker);
|
|
2071
2054
|
assert(array_[i].meta.LoadRelaxed() == 0);
|
|
2072
2055
|
}
|
|
2073
2056
|
#endif // MUST_FREE_HEAP_ALLOCATIONS
|
|
@@ -2089,11 +2072,9 @@ AutoHyperClockTable::~AutoHyperClockTable() {
|
|
|
2089
2072
|
usage_.FetchSubRelaxed(h.total_charge);
|
|
2090
2073
|
occupancy_.FetchSubRelaxed(1U);
|
|
2091
2074
|
was_populated[i] = true;
|
|
2092
|
-
if (!
|
|
2093
|
-
assert(
|
|
2094
|
-
|
|
2095
|
-
size_t next =
|
|
2096
|
-
GetNextFromNextWithShift(h.chain_next_with_shift.LoadRelaxed());
|
|
2075
|
+
if (!h.chain_next_with_shift.LoadRelaxed().IsEnd()) {
|
|
2076
|
+
assert(!h.chain_next_with_shift.LoadRelaxed().IsLocked());
|
|
2077
|
+
size_t next = h.chain_next_with_shift.LoadRelaxed().GetNext();
|
|
2097
2078
|
assert(!was_pointed_to[next]);
|
|
2098
2079
|
was_pointed_to[next] = true;
|
|
2099
2080
|
}
|
|
@@ -2105,9 +2086,8 @@ AutoHyperClockTable::~AutoHyperClockTable() {
|
|
|
2105
2086
|
break;
|
|
2106
2087
|
}
|
|
2107
2088
|
#ifndef NDEBUG // Extra invariant checking
|
|
2108
|
-
if (!
|
|
2109
|
-
size_t next =
|
|
2110
|
-
GetNextFromNextWithShift(h.head_next_with_shift.LoadRelaxed());
|
|
2089
|
+
if (!h.head_next_with_shift.LoadRelaxed().IsEnd()) {
|
|
2090
|
+
size_t next = h.head_next_with_shift.LoadRelaxed().GetNext();
|
|
2111
2091
|
assert(!was_pointed_to[next]);
|
|
2112
2092
|
was_pointed_to[next] = true;
|
|
2113
2093
|
}
|
|
@@ -2222,10 +2202,10 @@ bool AutoHyperClockTable::Grow(InsertState& state) {
|
|
|
2222
2202
|
// chain rewrite lock has been released.
|
|
2223
2203
|
size_t old_old_home = BottomNBits(grow_home, old_shift - 1);
|
|
2224
2204
|
for (;;) {
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2205
|
+
NextWithShift old_old_head =
|
|
2206
|
+
array_[old_old_home].head_next_with_shift.Load();
|
|
2207
|
+
if (old_old_head.GetShift() >= old_shift) {
|
|
2208
|
+
if (!old_old_head.IsLockedNotEnd()) {
|
|
2229
2209
|
break;
|
|
2230
2210
|
}
|
|
2231
2211
|
}
|
|
@@ -2285,8 +2265,7 @@ void AutoHyperClockTable::CatchUpLengthInfoNoWait(
|
|
|
2285
2265
|
if (published_usable_size < known_usable_grow_home) {
|
|
2286
2266
|
int old_shift = FloorLog2(next_usable_size - 1);
|
|
2287
2267
|
size_t old_home = BottomNBits(published_usable_size, old_shift);
|
|
2288
|
-
int shift =
|
|
2289
|
-
array_[old_home].head_next_with_shift.Load());
|
|
2268
|
+
int shift = array_[old_home].head_next_with_shift.Load().GetShift();
|
|
2290
2269
|
if (shift <= old_shift) {
|
|
2291
2270
|
// Not ready
|
|
2292
2271
|
break;
|
|
@@ -2437,9 +2416,10 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2437
2416
|
ChainRewriteLock zero_head_lock(&arr[old_home], yield_count_);
|
|
2438
2417
|
|
|
2439
2418
|
// Used for locking the one chain below
|
|
2440
|
-
|
|
2419
|
+
NextWithShift saved_one_head;
|
|
2441
2420
|
// One head has not been written to
|
|
2442
|
-
assert(arr[grow_home].head_next_with_shift.Load() ==
|
|
2421
|
+
assert(arr[grow_home].head_next_with_shift.Load() ==
|
|
2422
|
+
HandleImpl::kUnusedMarker);
|
|
2443
2423
|
|
|
2444
2424
|
// old_home will also the head of the new "zero chain" -- all entries in the
|
|
2445
2425
|
// "from" chain whose next hash bit is 0. grow_home will be head of the new
|
|
@@ -2461,7 +2441,7 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2461
2441
|
assert(cur == SIZE_MAX);
|
|
2462
2442
|
assert(chain_frontier_first == -1);
|
|
2463
2443
|
|
|
2464
|
-
|
|
2444
|
+
NextWithShift next_with_shift = zero_head_lock.GetSavedHead();
|
|
2465
2445
|
|
|
2466
2446
|
// Find a single representative for each target chain, or scan the whole
|
|
2467
2447
|
// chain if some target chain has no representative.
|
|
@@ -2474,16 +2454,16 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2474
2454
|
assert((cur == SIZE_MAX) == (zero_chain_frontier == SIZE_MAX &&
|
|
2475
2455
|
one_chain_frontier == SIZE_MAX));
|
|
2476
2456
|
|
|
2477
|
-
assert(
|
|
2457
|
+
assert(next_with_shift.GetShift() == old_shift);
|
|
2478
2458
|
|
|
2479
2459
|
// Check for end of original chain
|
|
2480
|
-
if (
|
|
2460
|
+
if (next_with_shift.IsEnd()) {
|
|
2481
2461
|
cur = SIZE_MAX;
|
|
2482
2462
|
break;
|
|
2483
2463
|
}
|
|
2484
2464
|
|
|
2485
2465
|
// next_with_shift is not End
|
|
2486
|
-
cur =
|
|
2466
|
+
cur = next_with_shift.GetNext();
|
|
2487
2467
|
|
|
2488
2468
|
if (BottomNBits(arr[cur].hashed_key[1], new_shift) == old_home) {
|
|
2489
2469
|
// Entry for zero chain
|
|
@@ -2522,10 +2502,10 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2522
2502
|
(zero_chain_frontier == SIZE_MAX && one_chain_frontier == SIZE_MAX));
|
|
2523
2503
|
|
|
2524
2504
|
// Always update one chain's head first (safe), and mark it as locked
|
|
2525
|
-
saved_one_head =
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2505
|
+
saved_one_head = one_chain_frontier != SIZE_MAX
|
|
2506
|
+
? NextWithShift::Make(one_chain_frontier, new_shift)
|
|
2507
|
+
: NextWithShift::MakeEnd(grow_home, new_shift);
|
|
2508
|
+
saved_one_head.Set<NextWithShift::LockedFlag>(true);
|
|
2529
2509
|
arr[grow_home].head_next_with_shift.Store(saved_one_head);
|
|
2530
2510
|
|
|
2531
2511
|
// Make sure length_info_ hasn't been updated too early, as we're about
|
|
@@ -2535,8 +2515,8 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2535
2515
|
// Try to set zero's head.
|
|
2536
2516
|
if (zero_head_lock.CasUpdate(
|
|
2537
2517
|
zero_chain_frontier != SIZE_MAX
|
|
2538
|
-
?
|
|
2539
|
-
:
|
|
2518
|
+
? NextWithShift::Make(zero_chain_frontier, new_shift)
|
|
2519
|
+
: NextWithShift::MakeEnd(old_home, new_shift),
|
|
2540
2520
|
yield_count_)) {
|
|
2541
2521
|
// Both heads successfully updated to new shift
|
|
2542
2522
|
break;
|
|
@@ -2570,10 +2550,10 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2570
2550
|
size_t& other_frontier = chain_frontier_first != 0
|
|
2571
2551
|
? /*&*/ zero_chain_frontier
|
|
2572
2552
|
: /*&*/ one_chain_frontier;
|
|
2573
|
-
|
|
2553
|
+
NextWithShift stop_before_or_new_tail =
|
|
2574
2554
|
other_frontier != SIZE_MAX
|
|
2575
|
-
? /*stop before*/
|
|
2576
|
-
: /*new tail*/
|
|
2555
|
+
? /*stop before*/ NextWithShift::Make(other_frontier, old_shift)
|
|
2556
|
+
: /*new tail*/ NextWithShift::MakeEnd(
|
|
2577
2557
|
chain_frontier_first == 0 ? old_home : grow_home, new_shift);
|
|
2578
2558
|
UpgradeShiftsOnRange(arr, first_frontier, stop_before_or_new_tail,
|
|
2579
2559
|
old_shift, new_shift);
|
|
@@ -2599,20 +2579,19 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2599
2579
|
? /*&*/ zero_chain_frontier
|
|
2600
2580
|
: /*&*/ one_chain_frontier;
|
|
2601
2581
|
assert(cur != first_frontier);
|
|
2602
|
-
assert(
|
|
2603
|
-
arr[first_frontier].chain_next_with_shift.Load()) ==
|
|
2582
|
+
assert(arr[first_frontier].chain_next_with_shift.Load().GetNext() ==
|
|
2604
2583
|
other_frontier);
|
|
2605
2584
|
|
|
2606
|
-
|
|
2585
|
+
NextWithShift next_with_shift = arr[cur].chain_next_with_shift.Load();
|
|
2607
2586
|
|
|
2608
2587
|
// Check for end of original chain
|
|
2609
|
-
if (
|
|
2588
|
+
if (next_with_shift.IsEnd()) {
|
|
2610
2589
|
// Can set upgraded tail on first chain
|
|
2611
|
-
|
|
2590
|
+
NextWithShift first_new_tail = NextWithShift::MakeEnd(
|
|
2612
2591
|
chain_frontier_first == 0 ? old_home : grow_home, new_shift);
|
|
2613
2592
|
arr[first_frontier].chain_next_with_shift.Store(first_new_tail);
|
|
2614
2593
|
// And upgrade remainder of other chain
|
|
2615
|
-
|
|
2594
|
+
NextWithShift other_new_tail = NextWithShift::MakeEnd(
|
|
2616
2595
|
chain_frontier_first != 0 ? old_home : grow_home, new_shift);
|
|
2617
2596
|
UpgradeShiftsOnRange(arr, other_frontier, other_new_tail, old_shift,
|
|
2618
2597
|
new_shift);
|
|
@@ -2621,7 +2600,7 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2621
2600
|
}
|
|
2622
2601
|
|
|
2623
2602
|
// next_with_shift is not End
|
|
2624
|
-
cur =
|
|
2603
|
+
cur = next_with_shift.GetNext();
|
|
2625
2604
|
|
|
2626
2605
|
int target_chain;
|
|
2627
2606
|
if (BottomNBits(arr[cur].hashed_key[1], new_shift) == old_home) {
|
|
@@ -2634,7 +2613,7 @@ void AutoHyperClockTable::SplitForGrow(size_t grow_home, size_t old_home,
|
|
|
2634
2613
|
}
|
|
2635
2614
|
if (target_chain == chain_frontier_first) {
|
|
2636
2615
|
// Found next entry to skip to on the first chain
|
|
2637
|
-
|
|
2616
|
+
NextWithShift skip_to = NextWithShift::Make(cur, new_shift);
|
|
2638
2617
|
arr[first_frontier].chain_next_with_shift.Store(skip_to);
|
|
2639
2618
|
first_frontier = cur;
|
|
2640
2619
|
// Upgrade other chain up to entry before that one
|
|
@@ -2675,17 +2654,17 @@ void AutoHyperClockTable::PurgeImplLocked(OpData* op_data,
|
|
|
2675
2654
|
|
|
2676
2655
|
HandleImpl* const arr = array_.Get();
|
|
2677
2656
|
|
|
2678
|
-
|
|
2679
|
-
assert(!
|
|
2680
|
-
int home_shift =
|
|
2657
|
+
NextWithShift next_with_shift = rewrite_lock.GetSavedHead();
|
|
2658
|
+
assert(!next_with_shift.IsEnd());
|
|
2659
|
+
int home_shift = next_with_shift.GetShift();
|
|
2681
2660
|
(void)home;
|
|
2682
2661
|
(void)home_shift;
|
|
2683
|
-
size_t next =
|
|
2662
|
+
size_t next = next_with_shift.GetNext();
|
|
2684
2663
|
assert(next < array_.Count());
|
|
2685
2664
|
HandleImpl* h = &arr[next];
|
|
2686
2665
|
HandleImpl* prev_to_keep = nullptr;
|
|
2687
2666
|
#ifndef NDEBUG
|
|
2688
|
-
|
|
2667
|
+
NextWithShift prev_to_keep_next_with_shift{};
|
|
2689
2668
|
#endif
|
|
2690
2669
|
// Whether there are entries between h and prev_to_keep that should be
|
|
2691
2670
|
// purged from the chain.
|
|
@@ -2743,13 +2722,13 @@ void AutoHyperClockTable::PurgeImplLocked(OpData* op_data,
|
|
|
2743
2722
|
// update any new entries just inserted in parallel.
|
|
2744
2723
|
// Can simply restart (GetSavedHead() already updated from CAS failure).
|
|
2745
2724
|
next_with_shift = rewrite_lock.GetSavedHead();
|
|
2746
|
-
assert(!
|
|
2747
|
-
next =
|
|
2725
|
+
assert(!next_with_shift.IsEnd());
|
|
2726
|
+
next = next_with_shift.GetNext();
|
|
2748
2727
|
assert(next < array_.Count());
|
|
2749
2728
|
h = &arr[next];
|
|
2750
2729
|
pending_purge = false;
|
|
2751
2730
|
assert(prev_to_keep == nullptr);
|
|
2752
|
-
assert(
|
|
2731
|
+
assert(next_with_shift.GetShift() == home_shift);
|
|
2753
2732
|
continue;
|
|
2754
2733
|
}
|
|
2755
2734
|
pending_purge = false;
|
|
@@ -2771,13 +2750,13 @@ void AutoHyperClockTable::PurgeImplLocked(OpData* op_data,
|
|
|
2771
2750
|
}
|
|
2772
2751
|
#endif
|
|
2773
2752
|
|
|
2774
|
-
assert(
|
|
2753
|
+
assert(next_with_shift.GetShift() == home_shift);
|
|
2775
2754
|
|
|
2776
2755
|
// Check for end marker
|
|
2777
|
-
if (
|
|
2756
|
+
if (next_with_shift.IsEnd()) {
|
|
2778
2757
|
h = nullptr;
|
|
2779
2758
|
} else {
|
|
2780
|
-
next =
|
|
2759
|
+
next = next_with_shift.GetNext();
|
|
2781
2760
|
assert(next < array_.Count());
|
|
2782
2761
|
h = &arr[next];
|
|
2783
2762
|
assert(h != prev_to_keep);
|
|
@@ -2849,7 +2828,7 @@ void AutoHyperClockTable::PurgeImpl(OpData* op_data, size_t home,
|
|
|
2849
2828
|
// Ensure we are at the correct home for the shift in effect for the
|
|
2850
2829
|
// chain head.
|
|
2851
2830
|
for (;;) {
|
|
2852
|
-
int shift =
|
|
2831
|
+
int shift = rewrite_lock.GetSavedHead().GetShift();
|
|
2853
2832
|
|
|
2854
2833
|
if (shift > home_shift) {
|
|
2855
2834
|
// Found a newer shift at candidate head, which must apply to us.
|
|
@@ -3045,14 +3024,14 @@ AutoHyperClockTable::HandleImpl* AutoHyperClockTable::DoInsert(
|
|
|
3045
3024
|
}
|
|
3046
3025
|
|
|
3047
3026
|
// Now insert into chain using head pointer
|
|
3048
|
-
|
|
3027
|
+
NextWithShift next_with_shift;
|
|
3049
3028
|
int home_shift = orig_home_shift;
|
|
3050
3029
|
|
|
3051
3030
|
// Might need to retry
|
|
3052
3031
|
for (int i = 0;; ++i) {
|
|
3053
3032
|
CHECK_TOO_MANY_ITERATIONS(i);
|
|
3054
3033
|
next_with_shift = arr[home].head_next_with_shift.Load();
|
|
3055
|
-
int shift =
|
|
3034
|
+
int shift = next_with_shift.GetShift();
|
|
3056
3035
|
|
|
3057
3036
|
if (UNLIKELY(shift != home_shift)) {
|
|
3058
3037
|
// NOTE: shift increases with table growth
|
|
@@ -3079,15 +3058,14 @@ AutoHyperClockTable::HandleImpl* AutoHyperClockTable::DoInsert(
|
|
|
3079
3058
|
}
|
|
3080
3059
|
|
|
3081
3060
|
// Values to update to
|
|
3082
|
-
|
|
3083
|
-
|
|
3061
|
+
NextWithShift head_next_with_shift = NextWithShift::Make(idx, home_shift);
|
|
3062
|
+
NextWithShift chain_next_with_shift = next_with_shift;
|
|
3084
3063
|
|
|
3085
3064
|
// Preserve the locked state in head, without propagating to chain next
|
|
3086
3065
|
// where it is meaningless (and not allowed)
|
|
3087
|
-
if (UNLIKELY((
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
chain_next_with_shift &= ~HandleImpl::kHeadLocked;
|
|
3066
|
+
if (UNLIKELY(next_with_shift.IsLockedNotEnd())) {
|
|
3067
|
+
head_next_with_shift.Set<NextWithShift::LockedFlag>(true);
|
|
3068
|
+
chain_next_with_shift.Set<NextWithShift::LockedFlag>(false);
|
|
3091
3069
|
}
|
|
3092
3070
|
|
|
3093
3071
|
arr[idx].chain_next_with_shift.Store(chain_next_with_shift);
|
|
@@ -3156,9 +3134,9 @@ AutoHyperClockTable::HandleImpl* AutoHyperClockTable::Lookup(
|
|
|
3156
3134
|
// of a loop as possible.
|
|
3157
3135
|
|
|
3158
3136
|
HandleImpl* const arr = array_.Get();
|
|
3159
|
-
|
|
3160
|
-
for (size_t i = 0; !
|
|
3161
|
-
HandleImpl* h = &arr[
|
|
3137
|
+
NextWithShift next_with_shift = arr[home].head_next_with_shift.LoadRelaxed();
|
|
3138
|
+
for (size_t i = 0; !next_with_shift.IsEnd() && i < 10; ++i) {
|
|
3139
|
+
HandleImpl* h = &arr[next_with_shift.IsEnd()];
|
|
3162
3140
|
// Attempt cheap key match without acquiring a read ref. This could give a
|
|
3163
3141
|
// false positive, which is re-checked after acquiring read ref, or false
|
|
3164
3142
|
// negative, which is re-checked in the full Lookup. Also, this is a
|
|
@@ -3203,7 +3181,7 @@ AutoHyperClockTable::HandleImpl* AutoHyperClockTable::Lookup(
|
|
|
3203
3181
|
// Read head or chain pointer
|
|
3204
3182
|
next_with_shift = h ? h->chain_next_with_shift.Load()
|
|
3205
3183
|
: arr[home].head_next_with_shift.Load();
|
|
3206
|
-
int shift =
|
|
3184
|
+
int shift = next_with_shift.GetShift();
|
|
3207
3185
|
|
|
3208
3186
|
// Make sure it's usable
|
|
3209
3187
|
size_t effective_home = home;
|
|
@@ -3257,10 +3235,10 @@ AutoHyperClockTable::HandleImpl* AutoHyperClockTable::Lookup(
|
|
|
3257
3235
|
}
|
|
3258
3236
|
|
|
3259
3237
|
// Check for end marker
|
|
3260
|
-
if (
|
|
3238
|
+
if (next_with_shift.IsEnd()) {
|
|
3261
3239
|
// To ensure we didn't miss anything in the chain, the end marker must
|
|
3262
3240
|
// point back to the correct home.
|
|
3263
|
-
if (LIKELY(
|
|
3241
|
+
if (LIKELY(next_with_shift.GetNext() == effective_home)) {
|
|
3264
3242
|
// Complete, clean iteration of the chain, not found.
|
|
3265
3243
|
// Clean up.
|
|
3266
3244
|
if (read_ref_on_chain) {
|
|
@@ -3276,7 +3254,7 @@ AutoHyperClockTable::HandleImpl* AutoHyperClockTable::Lookup(
|
|
|
3276
3254
|
}
|
|
3277
3255
|
|
|
3278
3256
|
// Follow the next and check for full key match, home match, or neither
|
|
3279
|
-
h = &arr[
|
|
3257
|
+
h = &arr[next_with_shift.GetNext()];
|
|
3280
3258
|
bool full_match_or_unknown = false;
|
|
3281
3259
|
if (MatchAndRef(&hashed_key, *h, shift, effective_home,
|
|
3282
3260
|
&full_match_or_unknown)) {
|
|
@@ -3600,8 +3578,7 @@ size_t AutoHyperClockTable::CalcMaxUsableLength(
|
|
|
3600
3578
|
|
|
3601
3579
|
namespace {
|
|
3602
3580
|
bool IsHeadNonempty(const AutoHyperClockTable::HandleImpl& h) {
|
|
3603
|
-
return !
|
|
3604
|
-
h.head_next_with_shift.LoadRelaxed());
|
|
3581
|
+
return !h.head_next_with_shift.LoadRelaxed().IsEnd();
|
|
3605
3582
|
}
|
|
3606
3583
|
bool IsEntryAtHome(const AutoHyperClockTable::HandleImpl& h, int shift,
|
|
3607
3584
|
size_t home) {
|
|
@@ -775,6 +775,7 @@ class AutoHyperClockTable : public BaseClockTable {
|
|
|
775
775
|
// chain--specifically the next entry in the chain.
|
|
776
776
|
// * The end of a chain is given a special "end" marker and refers back
|
|
777
777
|
// to the head of the chain.
|
|
778
|
+
// These decorated pointers use the NextWithShift bit field struct below.
|
|
778
779
|
//
|
|
779
780
|
// Why do we need shift on each pointer? To make Lookup wait-free, we need
|
|
780
781
|
// to be able to query a chain without missing anything, and preferably
|
|
@@ -794,47 +795,63 @@ class AutoHyperClockTable : public BaseClockTable {
|
|
|
794
795
|
// it is normal to see "under construction" entries on the chain, and it
|
|
795
796
|
// is not safe to read their hashed key without either a read reference
|
|
796
797
|
// on the entry or a rewrite lock on the chain.
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
//
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
798
|
+
struct NextWithShift : public BitFields<uint64_t, NextWithShift> {
|
|
799
|
+
// The "shift" associated with this decorated pointer (see description
|
|
800
|
+
// above).
|
|
801
|
+
using Shift = UnsignedBitField<NextWithShift, 6, NoPrevBitField>;
|
|
802
|
+
// Marker for the end of a chain. Must also (a) point back to the head of
|
|
803
|
+
// the chain (with end marker removed), and (b) set the LockedFlag
|
|
804
|
+
// (below), so that attempting to lock an empty chain has no effect (not
|
|
805
|
+
// needed, as the lock is only needed for removals).
|
|
806
|
+
using EndFlag = BoolBitField<NextWithShift, Shift>;
|
|
807
|
+
// Marker that some thread owning writes to the chain structure (except
|
|
808
|
+
// for inserts), but only if not an "end" pointer. Also called the
|
|
809
|
+
// "rewrite lock."
|
|
810
|
+
using LockedFlag = BoolBitField<NextWithShift, EndFlag>;
|
|
811
|
+
// The "next" associated with this decorated pointer, which is an index
|
|
812
|
+
// into the table's array_ (see description above).
|
|
813
|
+
using Next = UnsignedBitField<NextWithShift, 56, LockedFlag>;
|
|
814
|
+
|
|
815
|
+
bool IsLocked() const { return Get<LockedFlag>(); }
|
|
816
|
+
bool IsEnd() const {
|
|
817
|
+
// End flag should imply locked flag
|
|
818
|
+
assert(!Get<EndFlag>() || Get<LockedFlag>());
|
|
819
|
+
return Get<EndFlag>();
|
|
820
|
+
}
|
|
821
|
+
bool IsLockedNotEnd() const {
|
|
822
|
+
// NOTE: helping GCC to optimize this simpler code:
|
|
823
|
+
// return IsLocked() && !IsEnd();
|
|
824
|
+
constexpr U kEndFlag = U{1} << EndFlag::kBitOffset;
|
|
825
|
+
constexpr U kLockedFlag = U{1} << LockedFlag::kBitOffset;
|
|
826
|
+
return (underlying & (kEndFlag | kLockedFlag)) == kLockedFlag;
|
|
827
|
+
}
|
|
828
|
+
auto GetNext() const { return Get<Next>(); }
|
|
829
|
+
auto GetShift() const { return Get<Shift>(); }
|
|
830
|
+
|
|
831
|
+
static NextWithShift Make(size_t next, int shift) {
|
|
832
|
+
return NextWithShift{}.With<Next>(next).With<Shift>(
|
|
833
|
+
static_cast<uint8_t>(shift));
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
static NextWithShift MakeEnd(size_t next, int shift) {
|
|
837
|
+
return Make(next, shift).With<EndFlag>(true).With<LockedFlag>(true);
|
|
838
|
+
}
|
|
839
|
+
};
|
|
823
840
|
|
|
824
841
|
// A marker for head_next_with_shift that indicates this HandleImpl is
|
|
825
842
|
// heap allocated (standalone) rather than in the table.
|
|
826
|
-
static constexpr
|
|
843
|
+
static constexpr NextWithShift kStandaloneMarker{UINT64_MAX};
|
|
827
844
|
|
|
828
845
|
// A marker for head_next_with_shift indicating the head is not yet part
|
|
829
846
|
// of the usable table, or for chain_next_with_shift indicating that the
|
|
830
847
|
// entry is not present or is not yet part of a chain (must not be
|
|
831
848
|
// "shareable" state).
|
|
832
|
-
static constexpr
|
|
849
|
+
static constexpr NextWithShift kUnusedMarker{0};
|
|
833
850
|
|
|
834
851
|
// See above. The head pointer is logically independent of the rest of
|
|
835
852
|
// the entry, including the chain next pointer.
|
|
836
|
-
|
|
837
|
-
|
|
853
|
+
AcqRelBitFieldsAtomic<NextWithShift> head_next_with_shift{kUnusedMarker};
|
|
854
|
+
AcqRelBitFieldsAtomic<NextWithShift> chain_next_with_shift{kUnusedMarker};
|
|
838
855
|
|
|
839
856
|
// For supporting CreateStandalone and some fallback cases.
|
|
840
857
|
inline bool IsStandalone() const {
|