From 86fba2f66d78b4600ec1a2519a6ed052bd4c3d89 Mon Sep 17 00:00:00 2001 From: ivanmorozov333 Date: Wed, 17 Apr 2024 09:57:22 +0300 Subject: [PATCH] Revert "Prepare common library for locks (#1605)" This reverts commit 48e0cbfd5abfcffb81b2fd17a3a9e7b0edb33c74. --- ydb/core/client/locks_ut.cpp | 2 +- .../engine/minikql/minikql_engine_host.cpp | 2 +- .../kqp/runtime/kqp_stream_lookup_worker.h | 2 +- ydb/core/kqp/ut/opt/kqp_ne_ut.cpp | 1 - ydb/core/kqp/ut/scan/kqp_scan_ut.cpp | 1 - ydb/core/kqp/ut/scan/kqp_split_ut.cpp | 1 - ydb/core/sys_view/common/schema.h | 2 +- ydb/core/tx/columnshard/columnshard__init.cpp | 19 - .../columnshard/columnshard__progress_tx.cpp | 10 - ydb/core/tx/columnshard/columnshard_impl.cpp | 1 - ydb/core/tx/columnshard/columnshard_impl.h | 34 - ydb/core/tx/columnshard/columnshard_schema.h | 2 - .../tx/columnshard/transactions/locks_db.cpp | 5 - .../tx/columnshard/transactions/locks_db.h | 27 - ydb/core/tx/columnshard/transactions/ya.make | 6 + .../build_and_wait_dependencies_unit.cpp | 3 +- .../tx/datashard/datashard__engine_host.cpp | 2 +- .../datashard_active_transaction.cpp | 2 +- .../datashard/datashard_active_transaction.h | 2 +- .../datashard_counters.cpp} | 3 +- .../datashard_counters.h} | 0 ydb/core/tx/datashard/datashard_dep_tracker.h | 2 +- .../datashard/datashard_direct_transaction.h | 2 +- ydb/core/tx/datashard/datashard_impl.h | 4 +- ydb/core/tx/datashard/datashard_kqp.cpp | 2 +- ydb/core/tx/datashard/datashard_kqp.h | 5 - .../datashard_locks.cpp} | 33 +- .../locks.h => datashard/datashard_locks.h} | 18 +- ydb/core/tx/datashard/datashard_locks_db.cpp | 213 ++++++ ydb/core/tx/datashard/datashard_locks_db.h | 77 +- ydb/core/tx/datashard/datashard_user_table.h | 2 + ydb/core/tx/datashard/datashard_ut_locks.cpp | 4 +- .../datashard/datashard_write_operation.cpp | 2 +- .../tx/datashard/datashard_write_operation.h | 2 +- ydb/core/tx/datashard/key_conflicts.cpp | 2 +- ydb/core/tx/datashard/operation.h | 2 +- ydb/core/tx/datashard/range_avl_tree.cpp | 0 ydb/core/tx/datashard/range_avl_tree.h | 721 ++++++++++++++++++ ydb/core/tx/datashard/range_avl_tree_ut.cpp | 335 ++++++++ .../tx/{locks => datashard}/range_treap.cpp | 0 .../tx/{locks => datashard}/range_treap.h | 0 .../{locks => datashard}/range_treap_ut.cpp | 0 .../tx/{locks => datashard}/range_tree_base.h | 0 ydb/core/tx/datashard/read_iterator.h | 2 +- ydb/core/tx/{locks => datashard}/sys_tables.h | 0 .../ut_range_avl_tree/CMakeLists.txt | 19 + .../tx/datashard/ut_range_avl_tree/ya.make | 38 + .../datashard/ut_range_treap/CMakeLists.txt | 19 + .../ut_range_treap/ya.make | 2 +- ydb/core/tx/datashard/ya.make | 10 +- ydb/core/tx/locks/locks_db.cpp | 4 - ydb/core/tx/locks/locks_db.h | 198 ----- ydb/core/tx/locks/ya.make | 23 - ydb/core/tx/scheme_board/cache.cpp | 2 +- ydb/core/tx/scheme_cache/scheme_cache.h | 2 +- ydb/core/tx/tx_proxy/proxy.h | 2 +- ydb/services/metadata/manager/abstract.h | 2 +- 57 files changed, 1462 insertions(+), 414 deletions(-) delete mode 100644 ydb/core/tx/columnshard/transactions/locks_db.cpp delete mode 100644 ydb/core/tx/columnshard/transactions/locks_db.h rename ydb/core/tx/{locks/time_counters.cpp => datashard/datashard_counters.cpp} (61%) rename ydb/core/tx/{locks/time_counters.h => datashard/datashard_counters.h} (100%) rename ydb/core/tx/{locks/locks.cpp => datashard/datashard_locks.cpp} (98%) rename ydb/core/tx/{locks/locks.h => datashard/datashard_locks.h} (98%) create mode 100644 ydb/core/tx/datashard/range_avl_tree.cpp create mode 100644 ydb/core/tx/datashard/range_avl_tree.h create mode 100644 ydb/core/tx/datashard/range_avl_tree_ut.cpp rename ydb/core/tx/{locks => datashard}/range_treap.cpp (100%) rename ydb/core/tx/{locks => datashard}/range_treap.h (100%) rename ydb/core/tx/{locks => datashard}/range_treap_ut.cpp (100%) rename ydb/core/tx/{locks => datashard}/range_tree_base.h (100%) rename ydb/core/tx/{locks => datashard}/sys_tables.h (100%) create mode 100644 ydb/core/tx/datashard/ut_range_avl_tree/CMakeLists.txt create mode 100644 ydb/core/tx/datashard/ut_range_avl_tree/ya.make create mode 100644 ydb/core/tx/datashard/ut_range_treap/CMakeLists.txt rename ydb/core/tx/{locks => datashard}/ut_range_treap/ya.make (94%) delete mode 100644 ydb/core/tx/locks/locks_db.cpp delete mode 100644 ydb/core/tx/locks/locks_db.h delete mode 100644 ydb/core/tx/locks/ya.make diff --git a/ydb/core/client/locks_ut.cpp b/ydb/core/client/locks_ut.cpp index 575ed97b7722..2617461edaf7 100644 --- a/ydb/core/client/locks_ut.cpp +++ b/ydb/core/client/locks_ut.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include diff --git a/ydb/core/engine/minikql/minikql_engine_host.cpp b/ydb/core/engine/minikql/minikql_engine_host.cpp index f720c8780e12..bbddd3310ca3 100644 --- a/ydb/core/engine/minikql/minikql_engine_host.cpp +++ b/ydb/core/engine/minikql/minikql_engine_host.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include diff --git a/ydb/core/kqp/runtime/kqp_stream_lookup_worker.h b/ydb/core/kqp/runtime/kqp_stream_lookup_worker.h index adf44c052c19..b4bf0f47ef8a 100644 --- a/ydb/core/kqp/runtime/kqp_stream_lookup_worker.h +++ b/ydb/core/kqp/runtime/kqp_stream_lookup_worker.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include namespace NKikimr { diff --git a/ydb/core/kqp/ut/opt/kqp_ne_ut.cpp b/ydb/core/kqp/ut/opt/kqp_ne_ut.cpp index b9ffbfe0f237..68edda6abfbf 100644 --- a/ydb/core/kqp/ut/opt/kqp_ne_ut.cpp +++ b/ydb/core/kqp/ut/opt/kqp_ne_ut.cpp @@ -2,7 +2,6 @@ #include #include -#include namespace NKikimr::NKqp { diff --git a/ydb/core/kqp/ut/scan/kqp_scan_ut.cpp b/ydb/core/kqp/ut/scan/kqp_scan_ut.cpp index 2f5ebd4cd674..093889290bb3 100644 --- a/ydb/core/kqp/ut/scan/kqp_scan_ut.cpp +++ b/ydb/core/kqp/ut/scan/kqp_scan_ut.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include diff --git a/ydb/core/kqp/ut/scan/kqp_split_ut.cpp b/ydb/core/kqp/ut/scan/kqp_split_ut.cpp index 830cdc6ffd9b..81e67c27ccb4 100644 --- a/ydb/core/kqp/ut/scan/kqp_split_ut.cpp +++ b/ydb/core/kqp/ut/scan/kqp_split_ut.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include diff --git a/ydb/core/sys_view/common/schema.h b/ydb/core/sys_view/common/schema.h index 5737fec379aa..c2fbbc3a9f04 100644 --- a/ydb/core/sys_view/common/schema.h +++ b/ydb/core/sys_view/common/schema.h @@ -3,7 +3,7 @@ #include "path.h" #include -#include +#include namespace NKikimr { namespace NSysView { diff --git a/ydb/core/tx/columnshard/columnshard__init.cpp b/ydb/core/tx/columnshard/columnshard__init.cpp index 5da297db6ed2..6004845344cf 100644 --- a/ydb/core/tx/columnshard/columnshard__init.cpp +++ b/ydb/core/tx/columnshard/columnshard__init.cpp @@ -7,7 +7,6 @@ #include "engines/column_engine_logs.h" #include "export/manager/manager.h" #include -#include #include #include @@ -40,7 +39,6 @@ void TTxInit::SetDefaults() { Self->LastWriteId = TWriteId{0}; Self->LastPlannedStep = 0; Self->LastPlannedTxId = 0; - Self->LastCompletedTx = NOlap::TSnapshot::Zero(); Self->OwnerPathId = 0; Self->OwnerPath.clear(); Self->LongTxWrites.clear(); @@ -76,14 +74,6 @@ bool TTxInit::Precharge(TTransactionContext& txc) { ready = ready && Schema::GetSpecialValue(db, Schema::EValueIds::OwnerPathId, Self->OwnerPathId); ready = ready && Schema::GetSpecialValue(db, Schema::EValueIds::OwnerPath, Self->OwnerPath); - { - ui64 lastCompletedStep = 0; - ui64 lastCompletedTx = 0; - ready = ready && Schema::GetSpecialValue(db, Schema::EValueIds::LastCompletedStep, lastCompletedStep); - ready = ready && Schema::GetSpecialValue(db, Schema::EValueIds::LastCompletedTxId, lastCompletedTx); - Self->LastCompletedTx = NOlap::TSnapshot(lastCompletedStep, lastCompletedTx); - } - if (!ready) { return false; } @@ -188,15 +178,6 @@ bool TTxInit::ReadEverything(TTransactionContext& txc, const TActorContext& ctx) } } } - { - TMemoryProfileGuard g("TTxInit/LocksDB"); - if (txc.DB.GetScheme().GetTableInfo(Schema::Locks::TableId)) { - TColumnShardLocksDb locksDb(*Self, txc); - if (!Self->SysLocks.Load(locksDb)) { - return false; - } - } - } { TMemoryProfileGuard g("TTxInit/NDataSharing::TExportsManager"); diff --git a/ydb/core/tx/columnshard/columnshard__progress_tx.cpp b/ydb/core/tx/columnshard/columnshard__progress_tx.cpp index 0f842a0cb209..3cf0ffebec4a 100644 --- a/ydb/core/tx/columnshard/columnshard__progress_tx.cpp +++ b/ydb/core/tx/columnshard/columnshard__progress_tx.cpp @@ -32,12 +32,6 @@ class TColumnShard::TTxProgressTx : public TTransactionBase { if (!!plannedItem) { ui64 step = plannedItem->PlanStep; ui64 txId = plannedItem->TxId; - LastCompletedTx = NOlap::TSnapshot(step, txId); - if (LastCompletedTx > Self->LastCompletedTx) { - NIceDb::TNiceDb db(txc.DB); - Schema::SaveSpecialValue(db, Schema::EValueIds::LastCompletedStep, LastCompletedTx->GetPlanStep()); - Schema::SaveSpecialValue(db, Schema::EValueIds::LastCompletedTxId, LastCompletedTx->GetTxId()); - } TxOperator = Self->ProgressTxController->GetVerifiedTxOperator(txId); AFL_VERIFY(TxOperator->Progress(*Self, NOlap::TSnapshot(step, txId), txc)); @@ -57,16 +51,12 @@ class TColumnShard::TTxProgressTx : public TTransactionBase { if (TxOperator) { TxOperator->Complete(*Self, ctx); } - if (LastCompletedTx) { - Self->LastCompletedTx = std::max(*LastCompletedTx, Self->LastCompletedTx); - } Self->SetupIndexation(); } private: TTxController::ITransactionOperatior::TPtr TxOperator; const ui32 TabletTxNo; - std::optional LastCompletedTx; }; void TColumnShard::EnqueueProgressTx(const TActorContext& ctx) { diff --git a/ydb/core/tx/columnshard/columnshard_impl.cpp b/ydb/core/tx/columnshard/columnshard_impl.cpp index a37061db1789..3af0ad4154de 100644 --- a/ydb/core/tx/columnshard/columnshard_impl.cpp +++ b/ydb/core/tx/columnshard/columnshard_impl.cpp @@ -86,7 +86,6 @@ TColumnShard::TColumnShard(TTabletStorageInfo* info, const TActorId& tablet) , ScanCounters("Scan") , WritesMonitor(*this) , NormalizerController(StoragesManager, SubscribeCounters) - , SysLocks(this) { TabletCountersPtr.reset(new TProtobufTabletCounters< ESimpleCounters_descriptor, diff --git a/ydb/core/tx/columnshard/columnshard_impl.h b/ydb/core/tx/columnshard/columnshard_impl.h index cd54c887aedd..430ce0562a42 100644 --- a/ydb/core/tx/columnshard/columnshard_impl.h +++ b/ydb/core/tx/columnshard/columnshard_impl.h @@ -36,7 +36,6 @@ #include #include #include -#include #include #include @@ -282,37 +281,6 @@ class TColumnShard None /* "none" */ }; - void IncCounter(NColumnShard::EPercentileCounters counter, const TDuration& latency) const { - TabletCounters->Percentile()[counter].IncrementFor(latency.MicroSeconds()); - } - - void IncCounter(NDataShard::ESimpleCounters counter, ui64 num = 1) const { - TabletCounters->Simple()[counter].Add(num); - } - - // For syslocks - void IncCounter(NDataShard::ECumulativeCounters counter, ui64 num = 1) const { - TabletCounters->Cumulative()[counter].Increment(num); - } - - void IncCounter(NDataShard::EPercentileCounters counter, ui64 num) const { - TabletCounters->Percentile()[counter].IncrementFor(num); - } - - void IncCounter(NDataShard::EPercentileCounters counter, const TDuration& latency) const { - TabletCounters->Percentile()[counter].IncrementFor(latency.MilliSeconds()); - } - - inline TRowVersion LastCompleteTxVersion() const { - return TRowVersion(LastCompletedTx.GetPlanStep(), LastCompletedTx.GetTxId()); - } - - ui32 Generation() const { return Executor()->Generation(); } - - bool IsUserTable(const TTableId&) const { - return true; - } - private: void OverloadWriteFail(const EOverloadStatus overloadReason, const NEvWrite::TWriteData& writeData, const ui64 cookie, std::unique_ptr&& event, const TActorContext& ctx); EOverloadStatus CheckOverloaded(const ui64 tableId) const; @@ -465,7 +433,6 @@ class TColumnShard TWriteId LastWriteId = TWriteId{0}; ui64 LastPlannedStep = 0; ui64 LastPlannedTxId = 0; - NOlap::TSnapshot LastCompletedTx = NOlap::TSnapshot::Zero(); ui64 LastExportNo = 0; ui64 OwnerPathId = 0; @@ -513,7 +480,6 @@ class TColumnShard TSettings Settings; TLimits Limits; NOlap::TNormalizationController NormalizerController; - NDataShard::TSysLocks SysLocks; void TryRegisterMediatorTimeCast(); void UnregisterMediatorTimeCast(); diff --git a/ydb/core/tx/columnshard/columnshard_schema.h b/ydb/core/tx/columnshard/columnshard_schema.h index dd150bad9391..506fb92af814 100644 --- a/ydb/core/tx/columnshard/columnshard_schema.h +++ b/ydb/core/tx/columnshard/columnshard_schema.h @@ -74,8 +74,6 @@ struct Schema : NIceDb::Schema { LastExportNumber = 10, OwnerPathId = 11, OwnerPath = 12, - LastCompletedStep = 13, - LastCompletedTxId = 14, }; enum class EInsertTableIds : ui8 { diff --git a/ydb/core/tx/columnshard/transactions/locks_db.cpp b/ydb/core/tx/columnshard/transactions/locks_db.cpp deleted file mode 100644 index d3196304b86c..000000000000 --- a/ydb/core/tx/columnshard/transactions/locks_db.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "locks_db.h" - -namespace NKikimr::NColumnShard { - -} diff --git a/ydb/core/tx/columnshard/transactions/locks_db.h b/ydb/core/tx/columnshard/transactions/locks_db.h deleted file mode 100644 index 1df8fb957ff3..000000000000 --- a/ydb/core/tx/columnshard/transactions/locks_db.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include -#include - - -namespace NKikimr::NColumnShard { - -class TColumnShardLocksDb : public NLocks::TShardLocksDb { -private: - using TBase = NLocks::TShardLocksDb; - -public: - using TBase::TBase; - - void PersistRemoveLock(ui64 lockId) override { - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId).Delete(); - HasChanges_ = true; - } - - bool MayAddLock(ui64) override { - return true; - } - -}; - -} diff --git a/ydb/core/tx/columnshard/transactions/ya.make b/ydb/core/tx/columnshard/transactions/ya.make index 3b3a98aca4c9..fd4a30bc1741 100644 --- a/ydb/core/tx/columnshard/transactions/ya.make +++ b/ydb/core/tx/columnshard/transactions/ya.make @@ -12,6 +12,12 @@ PEERDIR( ydb/core/tx/columnshard/data_sharing/destination/events ) +IF (OS_WINDOWS) + CFLAGS( + -DKIKIMR_DISABLE_S3_OPS + ) +ENDIF() + YQL_LAST_ABI_VERSION() END() diff --git a/ydb/core/tx/datashard/build_and_wait_dependencies_unit.cpp b/ydb/core/tx/datashard/build_and_wait_dependencies_unit.cpp index ebdb2d18ede3..8f41a1da2a0a 100644 --- a/ydb/core/tx/datashard/build_and_wait_dependencies_unit.cpp +++ b/ydb/core/tx/datashard/build_and_wait_dependencies_unit.cpp @@ -1,9 +1,8 @@ #include "datashard_impl.h" +#include "datashard_counters.h" #include "datashard_pipeline.h" #include "execution_unit_ctors.h" -#include - namespace NKikimr { namespace NDataShard { diff --git a/ydb/core/tx/datashard/datashard__engine_host.cpp b/ydb/core/tx/datashard/datashard__engine_host.cpp index a999c477068e..8e2d2cbc4780 100644 --- a/ydb/core/tx/datashard/datashard__engine_host.cpp +++ b/ydb/core/tx/datashard/datashard__engine_host.cpp @@ -2,7 +2,7 @@ #include "datashard_impl.h" #include "datashard_user_db.h" #include "datashard__engine_host.h" -#include +#include "sys_tables.h" #include #include diff --git a/ydb/core/tx/datashard/datashard_active_transaction.cpp b/ydb/core/tx/datashard/datashard_active_transaction.cpp index e142ccbb7e8b..745010c5401d 100644 --- a/ydb/core/tx/datashard/datashard_active_transaction.cpp +++ b/ydb/core/tx/datashard/datashard_active_transaction.cpp @@ -2,11 +2,11 @@ #include "datashard_active_transaction.h" #include "datashard_kqp.h" +#include "datashard_locks.h" #include "datashard_impl.h" #include "datashard_failpoints.h" #include "key_conflicts.h" -#include #include namespace NKikimr { diff --git a/ydb/core/tx/datashard/datashard_active_transaction.h b/ydb/core/tx/datashard/datashard_active_transaction.h index 985ef24a9cdf..247b5335c0c9 100644 --- a/ydb/core/tx/datashard/datashard_active_transaction.h +++ b/ydb/core/tx/datashard/datashard_active_transaction.h @@ -1,7 +1,7 @@ #pragma once #include "datashard.h" -#include +#include "datashard_locks.h" #include "datashard__engine_host.h" #include "operation.h" diff --git a/ydb/core/tx/locks/time_counters.cpp b/ydb/core/tx/datashard/datashard_counters.cpp similarity index 61% rename from ydb/core/tx/locks/time_counters.cpp rename to ydb/core/tx/datashard/datashard_counters.cpp index 4c7d1b1ea05e..81c71ded164a 100644 --- a/ydb/core/tx/locks/time_counters.cpp +++ b/ydb/core/tx/datashard/datashard_counters.cpp @@ -1,4 +1,5 @@ -#include "time_counters.h" +#include "datashard_counters.h" +#include "datashard_impl.h" namespace NKikimr { namespace NDataShard { diff --git a/ydb/core/tx/locks/time_counters.h b/ydb/core/tx/datashard/datashard_counters.h similarity index 100% rename from ydb/core/tx/locks/time_counters.h rename to ydb/core/tx/datashard/datashard_counters.h diff --git a/ydb/core/tx/datashard/datashard_dep_tracker.h b/ydb/core/tx/datashard/datashard_dep_tracker.h index b48fcd3baaad..4c5a3746b02c 100644 --- a/ydb/core/tx/datashard/datashard_dep_tracker.h +++ b/ydb/core/tx/datashard/datashard_dep_tracker.h @@ -3,7 +3,7 @@ #include "datashard.h" #include "datashard_user_table.h" #include "datashard_active_transaction.h" -#include +#include "range_treap.h" #include diff --git a/ydb/core/tx/datashard/datashard_direct_transaction.h b/ydb/core/tx/datashard/datashard_direct_transaction.h index 6bdb518e351b..85cacda5f840 100644 --- a/ydb/core/tx/datashard/datashard_direct_transaction.h +++ b/ydb/core/tx/datashard/datashard_direct_transaction.h @@ -1,7 +1,7 @@ #pragma once #include "datashard_impl.h" -#include +#include "datashard_locks.h" #include "operation.h" #include diff --git a/ydb/core/tx/datashard/datashard_impl.h b/ydb/core/tx/datashard/datashard_impl.h index 87f1265ab3f7..b277cfe1ef43 100644 --- a/ydb/core/tx/datashard/datashard_impl.h +++ b/ydb/core/tx/datashard/datashard_impl.h @@ -1,6 +1,7 @@ #pragma once #include "datashard.h" +#include "datashard_locks.h" #include "datashard_trans_queue.h" #include "datashard_outreadset.h" #include "datashard_pipeline.h" @@ -28,7 +29,6 @@ #include #include #include -#include #include #include @@ -1588,7 +1588,7 @@ class TDataShard void AddUserTable(const TPathId& tableId, TUserTable::TPtr tableInfo) { TableInfos[tableId.LocalPathId] = tableInfo; - SysLocks.UpdateSchema(tableId, tableInfo->KeyColumnTypes); + SysLocks.UpdateSchema(tableId, *tableInfo); Pipeline.GetDepTracker().UpdateSchema(tableId, *tableInfo); } diff --git a/ydb/core/tx/datashard/datashard_kqp.cpp b/ydb/core/tx/datashard/datashard_kqp.cpp index c1ea663f75d1..cdd14d30f54c 100644 --- a/ydb/core/tx/datashard/datashard_kqp.cpp +++ b/ydb/core/tx/datashard/datashard_kqp.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/ydb/core/tx/datashard/datashard_kqp.h b/ydb/core/tx/datashard/datashard_kqp.h index b8cedf308d3a..54b9c4746958 100644 --- a/ydb/core/tx/datashard/datashard_kqp.h +++ b/ydb/core/tx/datashard/datashard_kqp.h @@ -3,13 +3,8 @@ #include "datashard.h" #include "datashard_active_transaction.h" -#include "operation.h" -#include "key_validator.h" -#include "datashard_user_db.h" - #include #include -#include #include diff --git a/ydb/core/tx/locks/locks.cpp b/ydb/core/tx/datashard/datashard_locks.cpp similarity index 98% rename from ydb/core/tx/locks/locks.cpp rename to ydb/core/tx/datashard/datashard_locks.cpp index a847fbee4731..2708f5a8bbdd 100644 --- a/ydb/core/tx/locks/locks.cpp +++ b/ydb/core/tx/datashard/datashard_locks.cpp @@ -1,7 +1,8 @@ -#include "locks.h" -#include "time_counters.h" - +#include "datashard_locks.h" +#include "datashard_impl.h" +#include "datashard_counters.h" #include + #include namespace NKikimr { @@ -576,8 +577,10 @@ void TLockLocker::RemoveOneLock(ui64 lockTxId, ILocksDb* db) { TLockInfo::TPtr txLock = it->second; TDuration lifetime = TAppData::TimeProvider->Now() - txLock->GetCreationTime(); - Self->IncCounter(COUNTER_LOCKS_LIFETIME, lifetime); - Self->IncCounter(COUNTER_LOCKS_REMOVED); + if (Self->TabletCounters) { + Self->IncCounter(COUNTER_LOCKS_LIFETIME, lifetime); + Self->IncCounter(COUNTER_LOCKS_REMOVED); + } ExpireQueue.Remove(txLock.Get()); if (txLock->InBrokenLocks) { @@ -614,11 +617,11 @@ void TLockLocker::RemoveLock(ui64 lockId, ILocksDb* db) { RemoveOneLock(lockId, db); } -void TLockLocker::UpdateSchema(const TPathId& tableId, const TVector& keyColumnTypes) { +void TLockLocker::UpdateSchema(const TPathId& tableId, const TUserTable& tableInfo) { TTableLocks::TPtr& table = Tables[tableId]; if (!table) table.Reset(new TTableLocks(tableId)); - table->UpdateKeyColumnsTypes(keyColumnTypes); + table->UpdateKeyColumnsTypes(tableInfo.KeyColumnTypes); } void TLockLocker::RemoveSchema(const TPathId& tableId) { @@ -670,7 +673,9 @@ void TLockLocker::ScheduleRemoveBrokenRanges(ui64 lockId, const TRowVersion& at) CleanupPending.push_back(lockId); } - Self->IncCounter(COUNTER_LOCKS_BROKEN); + if (Self->TabletCounters) { + Self->IncCounter(COUNTER_LOCKS_BROKEN); + } } void TLockLocker::RemoveSubscribedLock(ui64 lockId, ILocksDb* db) { @@ -749,7 +754,7 @@ TVector TSysLocks::ApplyLocks() { ++erases; } - if (erases > 0) { + if (erases > 0 && Self->TabletCounters) { Self->IncCounter(COUNTER_LOCKS_ERASED, erases); } @@ -782,7 +787,9 @@ TVector TSysLocks::ApplyLocks() { } else { if (shardLock) { Locker.AddShardLock(lock, Update->ReadTables); - Self->IncCounter(COUNTER_LOCKS_WHOLE_SHARD); + if (Self->TabletCounters) { + Self->IncCounter(COUNTER_LOCKS_WHOLE_SHARD); + } } else { for (const auto& key : Update->PointLocks) { Locker.AddPointLock(lock, key); @@ -831,11 +838,17 @@ TVector TSysLocks::ApplyLocks() { } void TSysLocks::UpdateCounters() { + if (!Self->TabletCounters) + return; + Self->IncCounter(COUNTER_LOCKS_ACTIVE_PER_SHARD, LocksCount()); Self->IncCounter(COUNTER_LOCKS_BROKEN_PER_SHARD, BrokenLocksCount()); } void TSysLocks::UpdateCounters(ui64 counter) { + if (!Self->TabletCounters) + return; + UpdateCounters(); if (TLock::IsError(counter)) { diff --git a/ydb/core/tx/locks/locks.h b/ydb/core/tx/datashard/datashard_locks.h similarity index 98% rename from ydb/core/tx/locks/locks.h rename to ydb/core/tx/datashard/datashard_locks.h index 16a9e9bde55a..c0b0aeebd450 100644 --- a/ydb/core/tx/locks/locks.h +++ b/ydb/core/tx/datashard/datashard_locks.h @@ -19,6 +19,8 @@ namespace NKikimr { namespace NDataShard { +struct TUserTable; + class ILocksDb { protected: ~ILocksDb() = default; @@ -74,6 +76,11 @@ class ILocksDb { class TLocksDataShard { public: + TLocksDataShard(TTabletCountersBase* const &tabletCounters) + : TabletCounters(tabletCounters) + { + } + virtual ~TLocksDataShard() = default; virtual void IncCounter(ECumulativeCounters counter, @@ -87,6 +94,8 @@ class TLocksDataShard { virtual bool IsUserTable(const TTableId& tableId) const = 0; virtual ui32 Generation() const = 0; virtual TRowVersion LastCompleteTxVersion() const = 0; + + TTabletCountersBase* const &TabletCounters; }; template @@ -94,7 +103,8 @@ class TLocksDataShardAdapter : public TLocksDataShard { public: TLocksDataShardAdapter(const T *self) - : Self(self) + : TLocksDataShard(self->TabletCounters) + , Self(self) { } @@ -590,7 +600,7 @@ class TLockLocker { }; } - void UpdateSchema(const TPathId& tableId, const TVector& keyColumnTypes); + void UpdateSchema(const TPathId& tableId, const TUserTable& tableInfo); void RemoveSchema(const TPathId& tableId); bool ForceShardLock(const TPathId& tableId) const; bool ForceShardLock(const TIntrusiveList& readTables) const; @@ -826,8 +836,8 @@ class TSysLocks { return Update->LockTxId; } - void UpdateSchema(const TPathId& tableId, const TVector& keyColumnTypes) { - Locker.UpdateSchema(tableId, keyColumnTypes); + void UpdateSchema(const TPathId& tableId, const TUserTable& tableInfo) { + Locker.UpdateSchema(tableId, tableInfo); } void RemoveSchema(const TPathId& tableId) { diff --git a/ydb/core/tx/datashard/datashard_locks_db.cpp b/ydb/core/tx/datashard/datashard_locks_db.cpp index 88af1639b092..5e5b21c173e9 100644 --- a/ydb/core/tx/datashard/datashard_locks_db.cpp +++ b/ydb/core/tx/datashard/datashard_locks_db.cpp @@ -2,4 +2,217 @@ namespace NKikimr::NDataShard { +bool TDataShardLocksDb::Load(TVector& rows) { + using Schema = TDataShard::Schema; + + NIceDb::TNiceDb db(DB); + + rows.clear(); + + // Load locks + THashMap lockIndex; + { + auto rowset = db.Table().Select(); + if (!rowset.IsReady()) { + return false; + } + while (!rowset.EndOfSet()) { + auto& lock = rows.emplace_back(); + lock.LockId = rowset.GetValue(); + lock.LockNodeId = rowset.GetValue(); + lock.Generation = rowset.GetValue(); + lock.Counter = rowset.GetValue(); + lock.CreateTs = rowset.GetValue(); + lock.Flags = rowset.GetValue(); + lockIndex[lock.LockId] = rows.size() - 1; + if (!rowset.Next()) { + return false; + } + } + } + + // Load ranges + { + auto rowset = db.Table().Select(); + if (!rowset.IsReady()) { + return false; + } + while (!rowset.EndOfSet()) { + auto lockId = rowset.GetValue(); + auto it = lockIndex.find(lockId); + if (it != lockIndex.end()) { + auto& lock = rows[it->second]; + auto& range = lock.Ranges.emplace_back(); + range.RangeId = rowset.GetValue(); + range.TableId.OwnerId = rowset.GetValue(); + range.TableId.LocalPathId = rowset.GetValue(); + range.Flags = rowset.GetValue(); + range.Data = rowset.GetValue(); + } + if (!rowset.Next()) { + return false; + } + } + } + + // Load conflicts + { + auto rowset = db.Table().Select(); + if (!rowset.IsReady()) { + return false; + } + while (!rowset.EndOfSet()) { + auto lockId = rowset.GetValue(); + auto it = lockIndex.find(lockId); + if (it != lockIndex.end()) { + auto& lock = rows[it->second]; + lock.Conflicts.push_back(rowset.GetValue()); + } + if (!rowset.Next()) { + return false; + } + } + } + + // Load volatile dependencies + if (db.HaveTable()) { + auto rowset = db.Table().Select(); + if (!rowset.IsReady()) { + return false; + } + while (!rowset.EndOfSet()) { + auto lockId = rowset.GetValue(); + auto it = lockIndex.find(lockId); + if (it != lockIndex.end()) { + auto& lock = rows[it->second]; + auto txId = rowset.GetValue(); + lock.VolatileDependencies.push_back(txId); + } + if (!rowset.Next()) { + return false; + } + } + } + + return true; +} + +bool TDataShardLocksDb::MayAddLock(ui64 lockId) { + for (auto& pr : Self.GetUserTables()) { + auto tid = pr.second->LocalTid; + // We cannot start a new lockId if it has any uncompacted data + if (DB.HasTxData(tid, lockId)) { + return false; + } + } + + return true; +} + +void TDataShardLocksDb::PersistAddLock(ui64 lockId, ui32 lockNodeId, ui32 generation, ui64 counter, ui64 createTs, ui64 flags) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId).Update( + NIceDb::TUpdate(lockNodeId), + NIceDb::TUpdate(generation), + NIceDb::TUpdate(counter), + NIceDb::TUpdate(createTs), + NIceDb::TUpdate(flags)); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistLockCounter(ui64 lockId, ui64 counter) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId).Update( + NIceDb::TUpdate(counter)); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistLockFlags(ui64 lockId, ui64 flags) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId).Update( + NIceDb::TUpdate(flags)); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistRemoveLock(ui64 lockId) { + // We remove lock changes unless it's managed by volatile tx manager + bool isVolatile = Self.GetVolatileTxManager().FindByCommitTxId(lockId); + if (!isVolatile) { + for (auto& pr : Self.GetUserTables()) { + auto tid = pr.second->LocalTid; + // Removing the lock also removes any uncommitted data + if (DB.HasOpenTx(tid, lockId)) { + DB.RemoveTx(tid, lockId); + Self.GetConflictsCache().GetTableCache(tid).RemoveUncommittedWrites(lockId, DB); + } + } + } + + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId).Delete(); + HasChanges_ = true; + + if (!isVolatile) { + Self.ScheduleRemoveLockChanges(lockId); + } +} + +void TDataShardLocksDb::PersistAddRange(ui64 lockId, ui64 rangeId, const TPathId& tableId, ui64 flags, const TString& data) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId, rangeId).Update( + NIceDb::TUpdate(tableId.OwnerId), + NIceDb::TUpdate(tableId.LocalPathId), + NIceDb::TUpdate(flags), + NIceDb::TUpdate(data)); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistRangeFlags(ui64 lockId, ui64 rangeId, ui64 flags) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId, rangeId).Update( + NIceDb::TUpdate(flags)); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistRemoveRange(ui64 lockId, ui64 rangeId) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId, rangeId).Delete(); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistAddConflict(ui64 lockId, ui64 otherLockId) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId, otherLockId).Update(); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistRemoveConflict(ui64 lockId, ui64 otherLockId) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId, otherLockId).Delete(); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistAddVolatileDependency(ui64 lockId, ui64 txId) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId, txId).Update(); + HasChanges_ = true; +} + +void TDataShardLocksDb::PersistRemoveVolatileDependency(ui64 lockId, ui64 txId) { + using Schema = TDataShard::Schema; + NIceDb::TNiceDb db(DB); + db.Table().Key(lockId, txId).Delete(); + HasChanges_ = true; +} + } // namespace NKikimr::NDataShard diff --git a/ydb/core/tx/datashard/datashard_locks_db.h b/ydb/core/tx/datashard/datashard_locks_db.h index 0cf56cc43beb..c9da2a157624 100644 --- a/ydb/core/tx/datashard/datashard_locks_db.h +++ b/ydb/core/tx/datashard/datashard_locks_db.h @@ -1,51 +1,48 @@ #pragma once -#include - #include "datashard_impl.h" namespace NKikimr::NDataShard { -class TDataShardLocksDb : public NLocks::TShardLocksDb { -private: - using TBase = NLocks::TShardLocksDb; - +class TDataShardLocksDb + : public ILocksDb +{ public: - using TBase::TBase; - - void PersistRemoveLock(ui64 lockId) override { - // We remove lock changes unless it's managed by volatile tx manager - bool isVolatile = Self.GetVolatileTxManager().FindByCommitTxId(lockId); - if (!isVolatile) { - for (auto& pr : Self.GetUserTables()) { - auto tid = pr.second->LocalTid; - // Removing the lock also removes any uncommitted data - if (DB.HasOpenTx(tid, lockId)) { - DB.RemoveTx(tid, lockId); - Self.GetConflictsCache().GetTableCache(tid).RemoveUncommittedWrites(lockId, DB); - } - } - } - - using Schema = TDataShard::Schema; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId).Delete(); - HasChanges_ = true; - - if (!isVolatile) { - Self.ScheduleRemoveLockChanges(lockId); - } - } + TDataShardLocksDb(TDataShard& self, TTransactionContext& txc) + : Self(self) + , DB(txc.DB) + { } - bool MayAddLock(ui64 lockId) override { - for (auto& pr : Self.GetUserTables()) { - auto tid = pr.second->LocalTid; - // We cannot start a new lockId if it has any uncompacted data - if (DB.HasTxData(tid, lockId)) { - return false; - } - } - return true; + bool HasChanges() const { + return HasChanges_; } + + bool Load(TVector& rows) override; + + bool MayAddLock(ui64 lockId) override; + + // Persist adding/removing a lock info + void PersistAddLock(ui64 lockId, ui32 lockNodeId, ui32 generation, ui64 counter, ui64 createTs, ui64 flags = 0) override; + void PersistLockCounter(ui64 lockId, ui64 counter) override; + void PersistLockFlags(ui64 lockId, ui64 flags) override; + void PersistRemoveLock(ui64 lockId) override; + + // Persist adding/removing info on locked ranges + void PersistAddRange(ui64 lockId, ui64 rangeId, const TPathId& tableId, ui64 flags = 0, const TString& data = {}) override; + void PersistRangeFlags(ui64 lockId, ui64 rangeId, ui64 flags) override; + void PersistRemoveRange(ui64 lockId, ui64 rangeId) override; + + // Persist a conflict, i.e. this lock must break some other lock on commit + void PersistAddConflict(ui64 lockId, ui64 otherLockId) override; + void PersistRemoveConflict(ui64 lockId, ui64 otherLockId) override; + + // Persist volatile dependencies, i.e. which undecided transactions must be waited for on commit + void PersistAddVolatileDependency(ui64 lockId, ui64 txId) override; + void PersistRemoveVolatileDependency(ui64 lockId, ui64 txId) override; + +private: + TDataShard& Self; + NTable::TDatabase& DB; + bool HasChanges_ = false; }; } // namespace NKikimr::NDataShard diff --git a/ydb/core/tx/datashard/datashard_user_table.h b/ydb/core/tx/datashard/datashard_user_table.h index a1e2927411ad..40a53145c998 100644 --- a/ydb/core/tx/datashard/datashard_user_table.h +++ b/ydb/core/tx/datashard/datashard_user_table.h @@ -1,5 +1,7 @@ #pragma once +#include "datashard.h" + #include #include #include diff --git a/ydb/core/tx/datashard/datashard_ut_locks.cpp b/ydb/core/tx/datashard/datashard_ut_locks.cpp index bc6a251f36c1..029af4fb409e 100644 --- a/ydb/core/tx/datashard/datashard_ut_locks.cpp +++ b/ydb/core/tx/datashard/datashard_ut_locks.cpp @@ -1,5 +1,5 @@ #include "defs.h" -#include +#include "datashard_locks.h" #include #include @@ -152,7 +152,7 @@ namespace NTest { TmpLockVec.emplace_back(TCell::Make(TmpLock.SchemeShard)); TmpLockVec.emplace_back(TCell::Make(TmpLock.PathId)); - Locks.UpdateSchema(tableId.PathId, DataShard.TableInfos[tid].KeyColumnTypes); + Locks.UpdateSchema(tableId.PathId, DataShard.TableInfos[tid]); } // diff --git a/ydb/core/tx/datashard/datashard_write_operation.cpp b/ydb/core/tx/datashard/datashard_write_operation.cpp index f419acffc5b0..5bd48c0a0311 100644 --- a/ydb/core/tx/datashard/datashard_write_operation.cpp +++ b/ydb/core/tx/datashard/datashard_write_operation.cpp @@ -2,7 +2,7 @@ #include "datashard_write_operation.h" #include "datashard_kqp.h" -#include +#include "datashard_locks.h" #include "datashard_impl.h" #include "datashard_failpoints.h" diff --git a/ydb/core/tx/datashard/datashard_write_operation.h b/ydb/core/tx/datashard/datashard_write_operation.h index 2f2ff5e81b3a..fa0bdf2fc951 100644 --- a/ydb/core/tx/datashard/datashard_write_operation.h +++ b/ydb/core/tx/datashard/datashard_write_operation.h @@ -1,7 +1,7 @@ #pragma once #include "datashard_impl.h" -#include +#include "datashard_locks.h" #include "datashard__engine_host.h" #include "datashard_user_db.h" #include "operation.h" diff --git a/ydb/core/tx/datashard/key_conflicts.cpp b/ydb/core/tx/datashard/key_conflicts.cpp index bdf24c7b6dc5..a252a1d9212c 100644 --- a/ydb/core/tx/datashard/key_conflicts.cpp +++ b/ydb/core/tx/datashard/key_conflicts.cpp @@ -1,5 +1,5 @@ #include "key_conflicts.h" -#include +#include "sys_tables.h" namespace NKikimr { namespace NDataShard { diff --git a/ydb/core/tx/datashard/operation.h b/ydb/core/tx/datashard/operation.h index 98fb5c1c1a6b..6c963da09a32 100644 --- a/ydb/core/tx/datashard/operation.h +++ b/ydb/core/tx/datashard/operation.h @@ -2,7 +2,7 @@ #include "defs.h" #include "datashard.h" -#include +#include "datashard_locks.h" #include "datashard_outreadset.h" #include "datashard_snapshots.h" #include "execution_unit_kind.h" diff --git a/ydb/core/tx/datashard/range_avl_tree.cpp b/ydb/core/tx/datashard/range_avl_tree.cpp new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/ydb/core/tx/datashard/range_avl_tree.h b/ydb/core/tx/datashard/range_avl_tree.h new file mode 100644 index 000000000000..459c59711f71 --- /dev/null +++ b/ydb/core/tx/datashard/range_avl_tree.h @@ -0,0 +1,721 @@ +#pragma once + +#include "range_tree_base.h" + +#include +#include +#include + +namespace NKikimr { +namespace NDataShard { + + template + class TRangeAvlTree : public TRangeTreeBase { + public: + TRangeAvlTree() = default; + + ~TRangeAvlTree() noexcept { + delete Root; + } + + private: + class TNode : public TIntrusiveListItem { + public: + TNode* Parent = nullptr; + TNode* Left = nullptr; + TNode* Right = nullptr; + i64 Height = 0; + TOwnedCellVec LeftKey; + TOwnedCellVec RightKey; + TOwnedCellVec MaxRightKey; + TValue Value; + EPrefixMode LeftMode; + EPrefixMode RightMode; + EPrefixMode MaxRightMode; + bool MaxRightTrivial; + + ~TNode() noexcept { + if (Left) { + delete Left; + } + if (Right) { + delete Right; + } + } + + TBorder LeftBorder() const noexcept { + return TBorder{ LeftKey, LeftMode }; + } + + TBorder RightBorder() const noexcept { + return TBorder{ RightKey, RightMode }; + } + + TBorder MaxRightBorder() const noexcept { + return TBorder{ MaxRightKey, MaxRightMode }; + } + + TRange ToRange() const noexcept { + return TRange(LeftKey, TBorder::IsInclusive(LeftMode), RightKey, TBorder::IsInclusive(RightMode)); + } + }; + + private: + /** + * Recomputes height for t only + */ + void RecomputeHeight(TNode* t) noexcept { + i64 lheight = t->Left ? t->Left->Height : 0; + i64 rheight = t->Right ? t->Right->Height : 0; + t->Height = Max(lheight, rheight) + 1; + } + + /** + * Recomputes heights for t and all its parents + */ + void RecomputeHeights(TNode* t) noexcept { + while (t) { + i64 lheight = t->Left ? t->Left->Height : 0; + i64 rheight = t->Right ? t->Right->Height : 0; + i64 height = Max(lheight, rheight) + 1; + + if (t->Height == height) { + return; + } + + t->Height = height; + t = t->Parent; + } + } + + /** + * Recomputes MaxRightKey for node t + */ + void RecomputeMaxRightKey(TNode* t) noexcept { + t->MaxRightKey = t->RightKey; + t->MaxRightMode = t->RightMode; + t->MaxRightTrivial = true; + if (t->Left && CompareBorders(t->MaxRightBorder(), t->Left->MaxRightBorder()) < 0) { + t->MaxRightKey = t->Left->MaxRightKey; + t->MaxRightMode = t->Left->MaxRightMode; + t->MaxRightTrivial = false; + } + if (t->Right && CompareBorders(t->MaxRightBorder(), t->Right->MaxRightBorder()) < 0) { + t->MaxRightKey = t->Right->MaxRightKey; + t->MaxRightMode = t->Right->MaxRightMode; + t->MaxRightTrivial = false; + } + } + + /** + * Extends MaxRightKey for node t + * + * Returns true when t->MaxRightKey is modified + */ + bool ExtendMaxRightKey(TNode* t, const TOwnedCellVec& rightKey, EPrefixMode rightMode) noexcept { + if (CompareBorders(t->MaxRightBorder(), TBorder{ rightKey, rightMode }) < 0) { + t->MaxRightKey = rightKey; + t->MaxRightMode = rightMode; + t->MaxRightTrivial = false; + return true; + } else { + return false; + } + } + + /** + * Extends MaxRightKey for node t and all parents + */ + void ExtendMaxRightKeys(TNode* t, const TOwnedCellVec& rightKey, EPrefixMode rightMode) noexcept { + while (t && ExtendMaxRightKey(t, rightKey, rightMode)) { + t = t->Parent; + } + } + + /** + * Extends RightKey for node t when necessary + * + * Updates MaxRightKey for all parents accordingly + */ + void ExtendRightKey(TNode* t, const TBorder& rightKey, TOwnedCellVec ownedRightKey) { + if (CompareBorders(t->RightBorder(), rightKey) < 0) { + t->RightKey = ownedRightKey; + t->RightMode = rightKey.Mode; + if (t->MaxRightTrivial) { + t->MaxRightKey = t->RightKey; + t->MaxRightMode = t->RightMode; + ExtendMaxRightKeys(t->Parent, t->RightKey, t->RightMode); + } else { + int cmp = CompareBorders(t->MaxRightBorder(), t->RightBorder()); + if (cmp <= 0) { + t->MaxRightKey = t->RightKey; + t->MaxRightTrivial = true; + t->MaxRightMode = t->RightMode; + } + if (cmp < 0) { + ExtendMaxRightKeys(t->Parent, t->RightKey, t->RightMode); + } + } + } + } + + TNode* FindFirstUnbalancedGrandParent(TNode* t) noexcept { + if (t == nullptr || t->Parent == nullptr) { + return nullptr; + } + + TNode* gp = t->Parent->Parent; + while (gp) { + i64 lheight = gp->Left ? gp->Left->Height : 0; + i64 rheight = gp->Right ? gp->Right->Height : 0; + i64 balance = lheight - rheight; + + if (balance < -1 || balance > +1) { + return t; + } + + t = t->Parent; + gp = gp->Parent; + } + + return nullptr; + } + + TNode* FindFirstUnbalancedAndRecomputeMaxRightKey(TNode* t) noexcept { + while (t) { + i64 lheight = t->Left ? t->Left->Height : 0; + i64 rheight = t->Right ? t->Right->Height : 0; + i64 balance = lheight - rheight; + + if (balance < -1 || balance > +1) { + // Note: we don't recompute MaxRightKey for unbalanced node + // It's going to be rebalanced and recomputed anyway + return t; + } + + RecomputeMaxRightKey(t); + t = t->Parent; + } + + return nullptr; + } + + /** + * Rebalances node n, which must have an unbalanced grandparent + */ + TNode* Rebalance(TNode* n) noexcept { + TNode* a; + TNode* b; + TNode* c; + TNode* t1; + TNode* t2; + TNode* t3; + TNode* t4; + TNode* keep; + + TNode* p = n->Parent; + TNode* gp = p->Parent; + TNode* ggp = gp->Parent; + + if (gp->Right == p) { + if (p->Right == n) { + // Right Right Case + a = gp; + b = p; + c = n; + t1 = gp->Left; + t2 = p->Left; + t3 = n->Left; + t4 = n->Right; + keep = n; + } else { + // Right Left Case + a = gp; + b = n; + c = p; + t1 = gp->Left; + t2 = n->Left; + t3 = n->Right; + t4 = p->Right; + keep = nullptr; + } + } else { + if (p->Right == n) { + // Left Right Case + a = p; + b = n; + c = gp; + t1 = p->Left; + t2 = n->Left; + t3 = n->Right; + t4 = gp->Right; + keep = nullptr; + } else { + // Left Left Case + a = n; + b = p; + c = gp; + t1 = n->Left; + t2 = n->Right; + t3 = p->Right; + t4 = gp->Right; + keep = n; + } + } + + if (ggp == nullptr) { + Root = b; + } else if (ggp->Left == gp) { + ggp->Left = b; + } else { + ggp->Right = b; + } + b->Parent = ggp; + + b->Left = a; + a->Parent = b; + + b->Right = c; + c->Parent = b; + + a->Left = t1; + if (t1 != nullptr) { + t1->Parent = a; + } + + a->Right = t2; + if (t2 != nullptr) { + t2->Parent = a; + } + + c->Left = t3; + if (t3 != nullptr) { + t3->Parent = c; + } + + c->Right = t4; + if (t4 != nullptr) { + t4->Parent = c; + } + + if (a != keep) { + RecomputeHeight(a); + RecomputeMaxRightKey(a); + } + + if (c != keep) { + RecomputeHeight(c); + RecomputeMaxRightKey(c); + } + + RecomputeHeight(b); + RecomputeMaxRightKey(b); + + RecomputeHeights(ggp); + return ggp; + } + + private: + void DoInsert( + const TBorder& leftKey, + const TBorder& rightKey, + TOwnedCellVec ownedLeftKey, + TOwnedCellVec ownedRightKey, + TValue value) + { + TNode* current = Root; + TNode* parent = nullptr; + bool isLeft = true; + while (current) { + int cmp = CompareBorders(leftKey, current->LeftBorder()); + if (cmp == 0 && value == current->Value) { + ++Stats_.Updates; + ExtendRightKey(current, rightKey, std::move(ownedRightKey)); + return; + } + + if (cmp < 0 || cmp == 0 && value < current->Value) { + isLeft = true; + parent = current; + current = current->Left; + } else { + isLeft = false; + parent = current; + current = current->Right; + } + } + + THolder p(new TNode); + p->Parent = parent; + p->Height = 1; + p->LeftKey = std::move(ownedLeftKey); + p->RightKey = std::move(ownedRightKey); + p->MaxRightKey = p->RightKey; + p->Value = value; + p->LeftMode = leftKey.Mode; + p->RightMode = rightKey.Mode; + p->MaxRightMode = p->RightMode; + p->MaxRightTrivial = true; + + TNode* inserted = p.Get(); + + if (parent) { + if (isLeft) { + parent->Left = p.Release(); + } else { + parent->Right = p.Release(); + } + + RecomputeHeights(parent); + ExtendMaxRightKeys(parent, inserted->RightKey, inserted->RightMode); + + if (TNode* ub = FindFirstUnbalancedGrandParent(inserted)) { + Rebalance(ub); + } + } else { + Root = p.Release(); + } + + Values[value].PushBack(inserted); + ++Size_; + ++Stats_.Inserts; + } + + void DoRemove(TNode* n) noexcept { + TNode* fixfrom; + + if (n->Right && (!n->Left || n->Left->Height <= n->Right->Height)) { + TNode* replacement = n->Right; + while (replacement->Left) { + replacement = replacement->Left; + } + + if (replacement->Parent == n) { + fixfrom = replacement; + } else { + fixfrom = replacement->Parent; + } + + DoRemoveNode(replacement, replacement->Right); + DoReplaceNode(n, replacement); + } else if (n->Left) { + TNode* replacement = n->Left; + while (replacement->Right) { + replacement = replacement->Right; + } + + if (replacement->Parent == n) { + fixfrom = replacement; + } else { + fixfrom = replacement->Parent; + } + + DoRemoveNode(replacement, replacement->Left); + DoReplaceNode(n, replacement); + } else { + fixfrom = n->Parent; + + DoRemoveNode(n, nullptr); + } + + delete n; + --Size_; + ++Stats_.Deletes; + + if (fixfrom == nullptr) { + return; + } + + RecomputeHeights(fixfrom); + + while (TNode* ub = FindFirstUnbalancedAndRecomputeMaxRightKey(fixfrom)) { + i64 lheight = ub->Left ? ub->Left->Height : 0; + i64 rheight = ub->Right ? ub->Right->Height : 0; + + if (rheight >= lheight) { + ub = ub->Right; + lheight = ub->Left ? ub->Left->Height : 0; + rheight = ub->Right ? ub->Right->Height : 0; + } else { + ub = ub->Left; + lheight = ub->Left ? ub->Left->Height : 0; + rheight = ub->Right ? ub->Right->Height : 0; + } + + if (rheight >= lheight) { + ub = ub->Right; + } else { + ub = ub->Left; + } + + fixfrom = Rebalance(ub); + } + } + + void DoRemoveNode(TNode* n, TNode* filler) noexcept { + TNode* parent = n->Parent; + if (parent) { + if (parent->Left == n) { + parent->Left = filler; + } else { + parent->Right = filler; + } + } else { + Root = filler; + } + + if (filler) { + filler->Parent = parent; + } + + n->Left = nullptr; + n->Right = nullptr; + } + + void DoReplaceNode(TNode* n, TNode* replacement) noexcept { + TNode* parent = n->Parent; + TNode* left = n->Left; + TNode* right = n->Right; + + replacement->Left = left; + if (left) { + left->Parent = replacement; + } + + replacement->Right = right; + if (right) { + right->Parent = replacement; + } + + replacement->Parent = parent; + + if (parent) { + if (parent->Left == n) { + parent->Left = replacement; + } else { + parent->Right = replacement; + } + } else { + Root = replacement; + } + + replacement->Height = n->Height; + n->Left = nullptr; + n->Right = nullptr; + } + + private: + /** + * Validates all invariants for subtree t + */ + std::tuple DoValidate(TNode* t) const noexcept { + int cmp; + TNode* leftMost = t; + TNode* rightMost = t; + TBorder maxRightBorder = t->RightBorder(); + bool maxRightTrivial = true; + i64 maxHeight = 1; + + if (auto* l = t->Left) { + Y_ABORT_UNLESS(l->Parent == t, "Left child parent is incorrect"); + cmp = this->CompareBorders(l->LeftBorder(), t->LeftBorder()); + Y_ABORT_UNLESS(cmp < 0 || cmp == 0 && l->Value < t->Value, "Left child must be smaller than t"); + TNode* leftRightMost; + std::tie(leftMost, leftRightMost) = DoValidate(l); + cmp = this->CompareBorders(leftRightMost->LeftBorder(), t->LeftBorder()); + Y_ABORT_UNLESS(cmp < 0 || cmp == 0 && leftRightMost->Value < t->Value, "Left child rightmost node must be smaller than t"); + cmp = this->CompareBorders(maxRightBorder, l->MaxRightBorder()); + if (cmp < 0) { + maxRightBorder = l->MaxRightBorder(); + maxRightTrivial = false; + } + maxHeight = Max(maxHeight, l->Height + 1); + } + + if (auto* r = t->Right) { + Y_ABORT_UNLESS(r->Parent == t, "Right child parent is incorrect"); + cmp = this->CompareBorders(t->LeftBorder(), r->LeftBorder()); + Y_ABORT_UNLESS(cmp < 0 || cmp == 0 && t->Value < r->Value, "Right child must be bigger than t"); + TNode* rightLeftMost; + std::tie(rightLeftMost, rightMost) = DoValidate(r); + cmp = this->CompareBorders(t->LeftBorder(), rightLeftMost->LeftBorder()); + Y_ABORT_UNLESS(cmp < 0 || cmp == 0 && t->Value < rightLeftMost->Value, "Right child leftmost node must be bigger than t"); + cmp = this->CompareBorders(maxRightBorder, r->MaxRightBorder()); + if (cmp < 0) { + maxRightBorder = r->MaxRightBorder(); + maxRightTrivial = false; + } + maxHeight = Max(maxHeight, r->Height + 1); + } + + Y_ABORT_UNLESS(t->Height == maxHeight, "Subtree height is incorrect"); + + cmp = this->CompareBorders(maxRightBorder, t->MaxRightBorder()); + Y_ABORT_UNLESS(cmp == 0, "Subtree must have max right key equal to the calculated max"); + Y_ABORT_UNLESS(maxRightTrivial == t->MaxRightTrivial, + "Subtree must have correct MaxRightTrivial flag (computed=%d, stored=%d)", + int(maxRightTrivial), int(t->MaxRightTrivial)); + + return { leftMost, rightMost }; + } + + public: + /** + * Validates all invariants for the tree, used for tests + */ + void Validate() const noexcept { + if (Root) { + Y_ABORT_UNLESS(Root->Parent == nullptr, "Root must not have a parent"); + DoValidate(Root); + } + } + + public: + void Clear() noexcept { + Values.clear(); + if (Root) { + delete std::exchange(Root, nullptr); + } + Size_ = 0; + } + + /** + * Adds mapping from the given range to the given value + */ + void AddRange(const TRange& range, TValue value) { + AddRange(range.ToOwnedRange(), std::move(value)); + } + + /** + * Adds mapping from the given range to the given value + */ + void AddRange(TOwnedRange range, TValue value) { + Y_ABORT_UNLESS(range.LeftKey.size() <= KeyTypes.size(), "Range left key is too large"); + Y_ABORT_UNLESS(range.RightKey.size() <= KeyTypes.size(), "Range right key is too large"); + + auto leftBorder = TBorder::MakeLeft(range.LeftKey, range.LeftInclusive); + auto rightBorder = TBorder::MakeRight(range.RightKey, range.RightInclusive); + + DoInsert( + leftBorder, + rightBorder, + std::move(range.LeftKey), + std::move(range.RightKey), + value); + } + + /** + * Removes all ranges with the given value + */ + void RemoveRanges(TValue value) { + auto it = Values.find(value); + if (it != Values.end()) { + while (!it->second.Empty()) { + DoRemove(it->second.PopFront()); + } + Values.erase(it); + } + } + + /** + * Calls callback(range, value) for each range in the tree + * + * Order is sorted by (range.Left, value, range.Right) tuples. + */ + template + void EachRange(TCallback&& callback) const { + if (Root) { + DoEachRange(Root, callback); + } + } + + /** + * Calls callback for each range with the given point + */ + template + void EachIntersection(TConstArrayRef point, TCallback&& callback) const { + EachIntersection(TRange(point, true, point, true), callback); + } + + /** + * Calls callback for each range intersecting with the query + */ + template + void EachIntersection(const TRange& range, TCallback&& callback) const { + if (Root) { + DoEachIntersection( + Root, + TBorder::MakeLeft(range.LeftKey, range.LeftInclusive), + TBorder::MakeRight(range.RightKey, range.RightInclusive), + callback); + } + } + + size_t Height() const { + return Root ? Root->Height : 0; + } + + private: + template + void DoEachRange(const TNode* t, TCallback&& callback) const { + if (t->Left) { + DoEachRange(t->Left, callback); + } + { + callback(t->ToRange(), t->Value); + } + if (t->Right) { + DoEachRange(t->Right, callback); + } + } + + template + void DoEachIntersection( + const TNode* t, + const TBorder& leftBorder, + const TBorder& rightBorder, + TCallback&& callback, + bool wentLeft = false) const + { + int cmp; + + if (wentLeft) { + cmp = CompareBorders(t->MaxRightBorder(), leftBorder); + if (cmp < 0) { + // There is no intersection with this whole subtree + return; + } + } + + if (t->Left) { + // Descend into the left subtree + // Note it will terminate on subtrees that have small MaxRightBorder + DoEachIntersection(t->Left, leftBorder, rightBorder, callback, true); + } + + cmp = CompareBorders(rightBorder, t->LeftBorder()); + if (cmp < 0) { + // There is no intersection with this node or the right subtree + return; + } + + // N.B. we avoid comparison with RightKey when it is equal to MaxRightKey. + if ((wentLeft && t->MaxRightTrivial) || + (cmp = CompareBorders(leftBorder, t->RightBorder())) <= 0) + { + callback(t->ToRange(), t->Value); + } + + if (t->Right) { + // Descend into the right subtree + DoEachIntersection(t->Right, leftBorder, rightBorder, callback); + } + } + + private: + TNode* Root = nullptr; + THashMap> Values; + }; + +} // namespace NDataShard +} // namespace NKikimr diff --git a/ydb/core/tx/datashard/range_avl_tree_ut.cpp b/ydb/core/tx/datashard/range_avl_tree_ut.cpp new file mode 100644 index 000000000000..012c980cd6ed --- /dev/null +++ b/ydb/core/tx/datashard/range_avl_tree_ut.cpp @@ -0,0 +1,335 @@ +#include "range_avl_tree.h" + +#include +#include +#include + +namespace NKikimr { +namespace NDataShard { + +namespace { + + TVector CreateSchema(size_t n) { + TVector schema; + auto type = NScheme::TTypeInfo(NScheme::NTypeIds::Uint64); + for (size_t i = 0; i < n; ++i) { + schema.emplace_back(type); + } + return schema; + } + +#if 0 + TVector CreateKey(std::initializer_list keys) { + TVector cells(Reserve(keys.size())); + for (ui64 key : keys) { + cells.emplace_back(TCell::Make(key)); + } + return cells; + } +#endif + + TVector CreateKey(ui64 key) { + TVector cells(Reserve(1)); + cells.emplace_back(TCell::Make(key)); + return cells; + } + + void PrintKey(TStringBuilder& builder, TConstArrayRef key, size_t columns) { + if (columns != 1) { + builder << '{'; + } + for (size_t i = 0; i < columns; ++i) { + if (i > 0) { + builder << ','; + } + if (i < key.size()) { + builder << key[i].AsValue(); + } else { + builder << "any"; + } + } + if (columns != 1) { + builder << '}'; + } + } + + void PrintRange(TStringBuilder& builder, const TRangeTreeBase::TRange& range, ui64 value, size_t columns) { + builder << (range.LeftInclusive ? '[' : '('); + PrintKey(builder, range.LeftKey, columns); + builder << ", "; + PrintKey(builder, range.RightKey, columns); + builder << (range.RightInclusive ? ']' : ')'); + builder << " -> "; + builder << value; + } + + class TRangesToString : public TStringBuilder { + public: + TRangesToString(TStringBuilder& builder, size_t columns) + : Builder(builder) + , Columns(columns) + { } + + void operator()(const TRangeTreeBase::TRange& range, ui64 value) { + if (Index++) { + Builder << ','; + Builder << ' '; + } + PrintRange(Builder, range, value, Columns); + } + + private: + TStringBuilder& Builder; + const size_t Columns; + size_t Index = 0; + }; + + TString AvlTreeToString(const TRangeAvlTree& tree) { + TStringBuilder builder; + tree.EachRange(TRangesToString(builder, tree.KeyColumns())); + return builder; + } + + template + TString IntersectionToString(const TRangeAvlTree& tree, const TNeedle& needle) { + TStringBuilder builder; + tree.EachIntersection(needle, TRangesToString(builder, tree.KeyColumns())); + return builder; + } + + struct TCheckValue { + ui64 Left, Right, Value; + + TCheckValue(ui64 left, ui64 right, ui64 value) + : Left(left) + , Right(right) + , Value(value) + { } + + TString ToString() const { + return TStringBuilder() << *this; + } + + friend inline bool operator==(const TCheckValue& a, const TCheckValue& b) { + return a.Left == b.Left && a.Right == b.Right && a.Value == b.Value; + } + + friend inline IOutputStream& operator<<(IOutputStream& out, const TCheckValue& check) { + out << '['; + out << check.Left; + out << ", "; + out << check.Right; + out << "] -> "; + out << check.Value; + return out; + } + }; + +} // namespace + +Y_UNIT_TEST_SUITE(TRangeAvlTree) { + + Y_UNIT_TEST(Simple) { + using TRange = TRangeTreeBase::TRange; + TRangeAvlTree tree; + tree.SetKeyTypes(CreateSchema(1)); + + tree.AddRange(TRange(CreateKey(1), true, CreateKey(10), true), 42); + tree.AddRange(TRange(CreateKey(2), true, CreateKey(20), true), 43); + tree.AddRange(TRange(CreateKey(3), true, CreateKey(30), true), 44); + tree.Validate(); + UNIT_ASSERT_VALUES_EQUAL(AvlTreeToString(tree), "[1, 10] -> 42, [2, 20] -> 43, [3, 30] -> 44"); + UNIT_ASSERT_VALUES_EQUAL(tree.Size(), 3u); + + tree.AddRange(TRange(CreateKey(2), true, CreateKey(40), true), 43); + tree.Validate(); + UNIT_ASSERT_VALUES_EQUAL(AvlTreeToString(tree), "[1, 10] -> 42, [2, 40] -> 43, [3, 30] -> 44"); + UNIT_ASSERT_VALUES_EQUAL(tree.Size(), 3u); + + UNIT_ASSERT_VALUES_EQUAL( + IntersectionToString(tree, CreateKey(1)), + "[1, 10] -> 42"); + + UNIT_ASSERT_VALUES_EQUAL( + IntersectionToString(tree, CreateKey(2)), + "[1, 10] -> 42, [2, 40] -> 43"); + + UNIT_ASSERT_VALUES_EQUAL( + IntersectionToString(tree, CreateKey(3)), + "[1, 10] -> 42, [2, 40] -> 43, [3, 30] -> 44"); + + UNIT_ASSERT_VALUES_EQUAL( + IntersectionToString(tree, CreateKey(15)), + "[2, 40] -> 43, [3, 30] -> 44"); + + UNIT_ASSERT_VALUES_EQUAL( + IntersectionToString(tree, CreateKey(35)), + "[2, 40] -> 43"); + + UNIT_ASSERT_VALUES_EQUAL( + IntersectionToString(tree, CreateKey(45)), + ""); + + tree.RemoveRanges(43); + tree.Validate(); + UNIT_ASSERT_VALUES_EQUAL(AvlTreeToString(tree), "[1, 10] -> 42, [3, 30] -> 44"); + UNIT_ASSERT_VALUES_EQUAL(tree.Size(), 2u); + + tree.RemoveRanges(42); + tree.Validate(); + UNIT_ASSERT_VALUES_EQUAL(AvlTreeToString(tree), "[3, 30] -> 44"); + UNIT_ASSERT_VALUES_EQUAL(tree.Size(), 1u); + + tree.RemoveRanges(44); + tree.Validate(); + UNIT_ASSERT_VALUES_EQUAL(AvlTreeToString(tree), ""); + UNIT_ASSERT_VALUES_EQUAL(tree.Size(), 0u); + } + + Y_UNIT_TEST(Sequential) { + using TRange = TRangeTreeBase::TRange; + TRangeAvlTree tree; + tree.SetKeyTypes(CreateSchema(1)); + + const size_t nRanges = 1000000; + for (size_t i = 0; i < nRanges; ++i) { + ui64 left = i + 1; + ui64 right = i + 1; + ui64 value = i + 1; + tree.AddRange(TRange(CreateKey(left), true, CreateKey(right), true), value); + } + tree.Validate(); + + auto buildStats = tree.Stats(); + Cerr << "NOTE: building tree of size " << tree.Size() + << " got height " << tree.Height() << " and needed " + << (buildStats.Inserts + buildStats.Updates + buildStats.Deletes) << " ops (" + << buildStats.Inserts << " inserts " + << buildStats.Updates << " updates " + << buildStats.Deletes << " deletes) and " + << buildStats.Comparisons << " comparisons (" + << double(buildStats.Comparisons) / double(buildStats.Inserts + buildStats.Updates + buildStats.Deletes) + << " per op)" + << Endl; + } + + Y_UNIT_TEST(Random) { + using TRange = TRangeTreeBase::TRange; + TRangeAvlTree tree; + tree.SetKeyTypes(CreateSchema(1)); + + using TCheckMap = TMap, ui64>; + TCheckMap map; // (left, value) -> right + using TCheckValues = THashMap>; + TCheckValues values; + + const ui64 nValues = 20; +#if 1 + const size_t nRanges = 10000; + const ui64 totalRangeSize = 10000; + const ui64 singleRangeMinSize = 100; + const ui64 singleRangeMaxSize = 5000; +#else + const size_t nRanges = 1000000; + const ui64 totalRangeSize = 1000000; + const ui64 singleRangeMinSize = 1; + const ui64 singleRangeMaxSize = 1; +#endif + + // Insert a bunch of values + for (size_t i = 0; i < nRanges; ++i) { + ui64 left = 1 + (RandomNumber() % totalRangeSize); + ui64 size = singleRangeMinSize + (RandomNumber() % (singleRangeMaxSize - singleRangeMinSize + 1)); + ui64 right = Min(left + size - 1, ui64(totalRangeSize)); + ui64 value = 1 + (RandomNumber() % nValues); + tree.AddRange(TRange(CreateKey(left), true, CreateKey(right), true), value); + // Add it to the classical map too + auto key = std::make_pair(left, value); + auto it = map.find(key); + if (it == map.end()) { + it = map.emplace(key, right).first; + values[value].emplace_back(it); + } else { + it->second = Max(it->second, right); + } + } + + // Remove some values with 10% probability + for (ui64 value = 1; value <= nValues; ++value) { + ui64 prio = RandomNumber() % 10; + if (prio == 0) { + tree.RemoveRanges(value); + // Remove it from the classical map too + for (auto it : values[value]) { + map.erase(it); + } + values.erase(value); + } + } + + auto buildStats = tree.Stats(); + Cerr << "NOTE: building tree of size " << tree.Size() + << " got height " << tree.Height() << " and needed " + << (buildStats.Inserts + buildStats.Updates + buildStats.Deletes) << " ops (" + << buildStats.Inserts << " inserts " + << buildStats.Updates << " updates " + << buildStats.Deletes << " deletes) and " + << buildStats.Comparisons << " comparisons (" + << double(buildStats.Comparisons) / double(buildStats.Inserts + buildStats.Updates + buildStats.Deletes) + << " per op)" + << Endl; + + // The resulting tree must be valid + tree.Validate(); + + // The resulting tree and shadow map must have the same size + UNIT_ASSERT_VALUES_EQUAL(tree.Size(), map.size()); + + auto checkIt = map.begin(); + tree.EachRange([&](const TRange& range, ui64 value) { + TCheckValue found{ range.LeftKey[0].AsValue(), range.RightKey[0].AsValue(), value }; + UNIT_ASSERT_C(checkIt != map.end(), "AvlTree has more values than the map, e.g.: " << found); + TCheckValue expected{ checkIt->first.first, checkIt->second, checkIt->first.second }; + UNIT_ASSERT_VALUES_EQUAL(found, expected); + ++checkIt; + }); + UNIT_ASSERT_C(checkIt == map.end(), "Map has more values than the tree"); + + // Let's find some intersections and verify them with brute force + for (size_t i = 0; i < 10; ++i) { + ui64 point = 1 + (RandomNumber() % totalRangeSize); + Cerr << "Checking point " << point << Endl; + auto checkIt = map.begin(); + tree.ResetStats(); + size_t foundCount = 0; + tree.EachIntersection(CreateKey(point), [&](const TRange& range, ui64 value) { + TCheckValue found{ range.LeftKey[0].AsValue(), range.RightKey[0].AsValue(), value }; + // Skip all map values that don't intersect with point + while (checkIt != map.end() && !(checkIt->first.first <= point && point <= checkIt->second)) { + ++checkIt; + } + UNIT_ASSERT_C(checkIt != map.end(), "AvlTree returned value that was not found in the map, e.g." << found); + TCheckValue expected{ checkIt->first.first, checkIt->second, checkIt->first.second }; + UNIT_ASSERT_VALUES_EQUAL_C(found, expected, "AvlTree returned a value that does not match with the map"); + ++checkIt; + ++foundCount; + }); + auto foundStats = tree.Stats(); + // Check if there is any other matching value + while (checkIt != map.end() && !(checkIt->first.first <= point && point <= checkIt->second)) { + ++checkIt; + } + UNIT_ASSERT_C(checkIt == map.end(), "Map has a value that was not returned from the tree, e.g." + << TCheckValue(checkIt->first.first, checkIt->second, checkIt->first.second)); + Cerr << "... found " << foundCount << " ranges, needed " + << foundStats.Comparisons << " comparisons (" + << double(foundStats.Comparisons) / double(Max(foundCount, ui64(1))) + << " per range)" + << Endl; + } + } + +} + +} // namespace NDataShard +} // namespace NKikimr diff --git a/ydb/core/tx/locks/range_treap.cpp b/ydb/core/tx/datashard/range_treap.cpp similarity index 100% rename from ydb/core/tx/locks/range_treap.cpp rename to ydb/core/tx/datashard/range_treap.cpp diff --git a/ydb/core/tx/locks/range_treap.h b/ydb/core/tx/datashard/range_treap.h similarity index 100% rename from ydb/core/tx/locks/range_treap.h rename to ydb/core/tx/datashard/range_treap.h diff --git a/ydb/core/tx/locks/range_treap_ut.cpp b/ydb/core/tx/datashard/range_treap_ut.cpp similarity index 100% rename from ydb/core/tx/locks/range_treap_ut.cpp rename to ydb/core/tx/datashard/range_treap_ut.cpp diff --git a/ydb/core/tx/locks/range_tree_base.h b/ydb/core/tx/datashard/range_tree_base.h similarity index 100% rename from ydb/core/tx/locks/range_tree_base.h rename to ydb/core/tx/datashard/range_tree_base.h diff --git a/ydb/core/tx/datashard/read_iterator.h b/ydb/core/tx/datashard/read_iterator.h index 8b2a4a2b7e5e..71f853f9795c 100644 --- a/ydb/core/tx/datashard/read_iterator.h +++ b/ydb/core/tx/datashard/read_iterator.h @@ -1,7 +1,7 @@ #pragma once #include "datashard.h" -#include +#include "datashard_locks.h" #include #include diff --git a/ydb/core/tx/locks/sys_tables.h b/ydb/core/tx/datashard/sys_tables.h similarity index 100% rename from ydb/core/tx/locks/sys_tables.h rename to ydb/core/tx/datashard/sys_tables.h diff --git a/ydb/core/tx/datashard/ut_range_avl_tree/CMakeLists.txt b/ydb/core/tx/datashard/ut_range_avl_tree/CMakeLists.txt new file mode 100644 index 000000000000..d863ebd18067 --- /dev/null +++ b/ydb/core/tx/datashard/ut_range_avl_tree/CMakeLists.txt @@ -0,0 +1,19 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + include(CMakeLists.darwin-arm64.txt) +elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) + include(CMakeLists.windows-x86_64.txt) +endif() diff --git a/ydb/core/tx/datashard/ut_range_avl_tree/ya.make b/ydb/core/tx/datashard/ut_range_avl_tree/ya.make new file mode 100644 index 000000000000..42434bd75a29 --- /dev/null +++ b/ydb/core/tx/datashard/ut_range_avl_tree/ya.make @@ -0,0 +1,38 @@ +UNITTEST_FOR(ydb/core/tx/datashard) + +FORK_SUBTESTS() + +SPLIT_FACTOR(1) + +IF (SANITIZER_TYPE == "thread" OR WITH_VALGRIND) + TIMEOUT(3600) + SIZE(LARGE) + TAG(ya:fat) + REQUIREMENTS(ram:16) +ELSE() + TIMEOUT(600) + SIZE(MEDIUM) +ENDIF() + +PEERDIR( + ydb/core/tx/datashard/ut_common + library/cpp/getopt + library/cpp/regex/pcre + library/cpp/svnversion + ydb/core/kqp/ut/common + ydb/core/testlib/default + ydb/core/tx + ydb/library/yql/public/udf/service/exception_policy + ydb/public/lib/yson_value + ydb/public/sdk/cpp/client/ydb_result +) + +YQL_LAST_ABI_VERSION() + +SRCS( + range_avl_tree_ut.cpp +) + +REQUIREMENTS(ram:32) + +END() diff --git a/ydb/core/tx/datashard/ut_range_treap/CMakeLists.txt b/ydb/core/tx/datashard/ut_range_treap/CMakeLists.txt new file mode 100644 index 000000000000..d863ebd18067 --- /dev/null +++ b/ydb/core/tx/datashard/ut_range_treap/CMakeLists.txt @@ -0,0 +1,19 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + include(CMakeLists.darwin-arm64.txt) +elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) + include(CMakeLists.windows-x86_64.txt) +endif() diff --git a/ydb/core/tx/locks/ut_range_treap/ya.make b/ydb/core/tx/datashard/ut_range_treap/ya.make similarity index 94% rename from ydb/core/tx/locks/ut_range_treap/ya.make rename to ydb/core/tx/datashard/ut_range_treap/ya.make index b6aba4f21439..bd8648affdb4 100644 --- a/ydb/core/tx/locks/ut_range_treap/ya.make +++ b/ydb/core/tx/datashard/ut_range_treap/ya.make @@ -1,4 +1,4 @@ -UNITTEST_FOR(ydb/core/tx/locks) +UNITTEST_FOR(ydb/core/tx/datashard) FORK_SUBTESTS() diff --git a/ydb/core/tx/datashard/ya.make b/ydb/core/tx/datashard/ya.make index d89f6fa8e5fe..49541b974798 100644 --- a/ydb/core/tx/datashard/ya.make +++ b/ydb/core/tx/datashard/ya.make @@ -74,9 +74,12 @@ SRCS( datashard_change_receiving.cpp datashard_change_sender_activation.cpp datashard_change_sending.cpp + datashard_counters.cpp datashard_loans.cpp datashard_locks_db.cpp datashard_locks_db.h + datashard_locks.h + datashard_locks.cpp datashard_split_dst.cpp datashard_split_src.cpp datashard_switch_mvcc_state.cpp @@ -124,7 +127,7 @@ SRCS( datashard_repl_offsets_client.cpp datashard_repl_offsets_server.cpp datashard_subdomain_path_id.cpp - datashard_write_operation.cpp + datashard_write_operation.cpp datashard_txs.h datashard.cpp datashard.h @@ -181,7 +184,9 @@ SRCS( receive_snapshot_unit.cpp remove_lock_change_records.cpp remove_locks.cpp + range_avl_tree.cpp range_ops.cpp + range_treap.cpp read_iterator.h restore_unit.cpp setup_sys_locks.h @@ -240,7 +245,6 @@ PEERDIR( ydb/core/tablet ydb/core/tablet_flat ydb/core/tx/long_tx_service/public - ydb/core/tx/locks ydb/core/util ydb/core/wrappers ydb/core/ydb_convert @@ -291,7 +295,9 @@ RECURSE_FOR_TESTS( ut_minikql ut_minstep ut_order + ut_range_avl_tree ut_range_ops + ut_range_treap ut_read_iterator ut_read_table ut_reassign diff --git a/ydb/core/tx/locks/locks_db.cpp b/ydb/core/tx/locks/locks_db.cpp deleted file mode 100644 index 1b015e3e377b..000000000000 --- a/ydb/core/tx/locks/locks_db.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "locks_db.h" - -namespace NKikimr::NLocks { -} diff --git a/ydb/core/tx/locks/locks_db.h b/ydb/core/tx/locks/locks_db.h deleted file mode 100644 index 1a78958b13bf..000000000000 --- a/ydb/core/tx/locks/locks_db.h +++ /dev/null @@ -1,198 +0,0 @@ -#pragma once - -#include "locks.h" -#include -#include - -namespace NKikimr::NLocks { - -template -class TShardLocksDb : public NKikimr::NDataShard::ILocksDb { -public: - TShardLocksDb(TShard& self, NTabletFlatExecutor::TTransactionContext& txc) - : Self(self) - , DB(txc.DB) - { } - - bool HasChanges() const { - return HasChanges_; - } - - bool Load(TVector& rows) override { - using Schema = TSchemaDescription; - - NIceDb::TNiceDb db(DB); - - rows.clear(); - - // Load locks - THashMap lockIndex; - { - auto rowset = db.Table().Select(); - if (!rowset.IsReady()) { - return false; - } - while (!rowset.EndOfSet()) { - auto& lock = rows.emplace_back(); - lock.LockId = rowset.template GetValue(); - lock.LockNodeId = rowset.template GetValue(); - lock.Generation = rowset.template GetValue(); - lock.Counter = rowset.template GetValue(); - lock.CreateTs = rowset.template GetValue(); - lock.Flags = rowset.template GetValue(); - lockIndex[lock.LockId] = rows.size() - 1; - if (!rowset.Next()) { - return false; - } - } - } - - // Load ranges - { - auto rowset = db.Table().Select(); - if (!rowset.IsReady()) { - return false; - } - while (!rowset.EndOfSet()) { - auto lockId = rowset.template GetValue(); - auto it = lockIndex.find(lockId); - if (it != lockIndex.end()) { - auto& lock = rows[it->second]; - auto& range = lock.Ranges.emplace_back(); - range.RangeId = rowset.template GetValue(); - range.TableId.OwnerId = rowset.template GetValue(); - range.TableId.LocalPathId = rowset.template GetValue(); - range.Flags = rowset.template GetValue(); - range.Data = rowset.template GetValue(); - } - if (!rowset.Next()) { - return false; - } - } - } - - // Load conflicts - { - auto rowset = db.Table().Select(); - if (!rowset.IsReady()) { - return false; - } - while (!rowset.EndOfSet()) { - auto lockId = rowset.template GetValue(); - auto it = lockIndex.find(lockId); - if (it != lockIndex.end()) { - auto& lock = rows[it->second]; - lock.Conflicts.push_back(rowset.template GetValue()); - } - if (!rowset.Next()) { - return false; - } - } - } - - // Load volatile dependencies - if (db.HaveTable()) { - auto rowset = db.Table().Select(); - if (!rowset.IsReady()) { - return false; - } - while (!rowset.EndOfSet()) { - auto lockId = rowset.template GetValue(); - auto it = lockIndex.find(lockId); - if (it != lockIndex.end()) { - auto& lock = rows[it->second]; - auto txId = rowset.template GetValue(); - lock.VolatileDependencies.push_back(txId); - } - if (!rowset.Next()) { - return false; - } - } - } - - return true; - } - - void PersistAddLock(ui64 lockId, ui32 lockNodeId, ui32 generation, ui64 counter, ui64 createTs, ui64 flags = 0) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId).Update( - NIceDb::TUpdate(lockNodeId), - NIceDb::TUpdate(generation), - NIceDb::TUpdate(counter), - NIceDb::TUpdate(createTs), - NIceDb::TUpdate(flags)); - HasChanges_ = true; - } - - void PersistLockCounter(ui64 lockId, ui64 counter) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId).Update( - NIceDb::TUpdate(counter)); - HasChanges_ = true; - } - - // Persist adding/removing info on locked ranges - void PersistAddRange(ui64 lockId, ui64 rangeId, const TPathId& tableId, ui64 flags = 0, const TString& data = {}) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId, rangeId).Update( - NIceDb::TUpdate(tableId.OwnerId), - NIceDb::TUpdate(tableId.LocalPathId), - NIceDb::TUpdate(flags), - NIceDb::TUpdate(data)); - HasChanges_ = true; - } - - void PersistRangeFlags(ui64 lockId, ui64 rangeId, ui64 flags) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId, rangeId).Update( - NIceDb::TUpdate(flags)); - HasChanges_ = true; - } - - void PersistRemoveRange(ui64 lockId, ui64 rangeId) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId, rangeId).Delete(); - HasChanges_ = true; - } - - // Persist a conflict, i.e. this lock must break some other lock on commit - void PersistAddConflict(ui64 lockId, ui64 otherLockId) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId, otherLockId).Update(); - HasChanges_ = true; - } - - void PersistRemoveConflict(ui64 lockId, ui64 otherLockId) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId, otherLockId).Delete(); - HasChanges_ = true; - } - - // Persist volatile dependencies, i.e. which undecided transactions must be waited for on commit - void PersistAddVolatileDependency(ui64 lockId, ui64 txId) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId, txId).Update(); - HasChanges_ = true; - } - - void PersistRemoveVolatileDependency(ui64 lockId, ui64 txId) override { - using Schema = TSchemaDescription; - NIceDb::TNiceDb db(DB); - db.Table().Key(lockId, txId).Delete(); - HasChanges_ = true; - } - -protected: - TShard& Self; - NTable::TDatabase& DB; - bool HasChanges_ = false; -}; -} diff --git a/ydb/core/tx/locks/ya.make b/ydb/core/tx/locks/ya.make deleted file mode 100644 index afded9eea5e1..000000000000 --- a/ydb/core/tx/locks/ya.make +++ /dev/null @@ -1,23 +0,0 @@ -LIBRARY() - -SRCS( - locks.cpp - locks_db.cpp - time_counters.cpp - range_treap.cpp -) - - -PEERDIR( - ydb/core/protos - ydb/core/tablet_flat -) - -YQL_LAST_ABI_VERSION() - -END() - - -RECURSE_FOR_TESTS( - ut_range_treap -) diff --git a/ydb/core/tx/scheme_board/cache.cpp b/ydb/core/tx/scheme_board/cache.cpp index 96443917beb6..8692568da184 100644 --- a/ydb/core/tx/scheme_board/cache.cpp +++ b/ydb/core/tx/scheme_board/cache.cpp @@ -5,7 +5,7 @@ #include "monitorable_actor.h" #include "subscriber.h" -#include +#include #include #include #include diff --git a/ydb/core/tx/scheme_cache/scheme_cache.h b/ydb/core/tx/scheme_cache/scheme_cache.h index 687a6e158e76..5ccea3f421a1 100644 --- a/ydb/core/tx/scheme_cache/scheme_cache.h +++ b/ydb/core/tx/scheme_cache/scheme_cache.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/ydb/core/tx/tx_proxy/proxy.h b/ydb/core/tx/tx_proxy/proxy.h index 8ae80a9c1949..e757bc3306ad 100644 --- a/ydb/core/tx/tx_proxy/proxy.h +++ b/ydb/core/tx/tx_proxy/proxy.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/ydb/services/metadata/manager/abstract.h b/ydb/services/metadata/manager/abstract.h index 16ce69160259..71c49dbf8225 100644 --- a/ydb/services/metadata/manager/abstract.h +++ b/ydb/services/metadata/manager/abstract.h @@ -3,7 +3,7 @@ #include "table_record.h" #include -#include +#include #include #include #include