@@ -750,6 +750,39 @@ void TDataShard::PersistChangeRecord(NIceDb::TNiceDb& db, const TChangeRecord& r
750
750
NIceDb::TUpdate<Schema::ChangeRecordDetails::Kind>(record.GetKind ()),
751
751
NIceDb::TUpdate<Schema::ChangeRecordDetails::Body>(record.GetBody ()),
752
752
NIceDb::TUpdate<Schema::ChangeRecordDetails::Source>(record.GetSource ()));
753
+
754
+ auto res = ChangesQueue.emplace (record.GetOrder (), record);
755
+ Y_VERIFY_S (res.second , " Duplicate change record: " << record.GetOrder ());
756
+
757
+ if (res.first ->second .SchemaVersion ) {
758
+ res.first ->second .SchemaSnapshotAcquired = SchemaSnapshotManager.AcquireReference (
759
+ TSchemaSnapshotKey (res.first ->second .TableId , res.first ->second .SchemaVersion ));
760
+ }
761
+
762
+ if (CommittingChangeRecords.empty ()) {
763
+ db.GetDatabase ().OnCommit ([this ] {
764
+ CommittingChangeRecords.clear ();
765
+ });
766
+ db.GetDatabase ().OnRollback ([this ] {
767
+ for (const auto order : CommittingChangeRecords) {
768
+ auto cIt = ChangesQueue.find (order);
769
+ Y_VERIFY_S (cIt != ChangesQueue.end (), " Cannot find change record: " << order);
770
+
771
+ if (cIt->second .SchemaSnapshotAcquired ) {
772
+ const auto snapshotKey = TSchemaSnapshotKey (cIt->second .TableId , cIt->second .SchemaVersion );
773
+ if (const auto last = SchemaSnapshotManager.ReleaseReference (snapshotKey)) {
774
+ ScheduleRemoveSchemaSnapshot (snapshotKey);
775
+ }
776
+ }
777
+
778
+ ChangesQueue.erase (cIt);
779
+ }
780
+
781
+ CommittingChangeRecords.clear ();
782
+ });
783
+ }
784
+
785
+ CommittingChangeRecords.push_back (record.GetOrder ());
753
786
} else {
754
787
auto & state = LockChangeRecords[lockId];
755
788
Y_ABORT_UNLESS (state.Changes .empty () || state.Changes .back ().LockOffset < record.GetLockOffset (),
@@ -829,6 +862,14 @@ void TDataShard::CommitLockChangeRecords(NIceDb::TNiceDb& db, ui64 lockId, ui64
829
862
committed.Step = rowVersion.Step ;
830
863
committed.TxId = rowVersion.TxId ;
831
864
collected.push_back (committed);
865
+
866
+ auto res = ChangesQueue.emplace (committed.Order , committed);
867
+ Y_VERIFY_S (res.second , " Duplicate change record: " << committed.Order );
868
+
869
+ if (res.first ->second .SchemaVersion ) {
870
+ res.first ->second .SchemaSnapshotAcquired = SchemaSnapshotManager.AcquireReference (
871
+ TSchemaSnapshotKey (res.first ->second .TableId , res.first ->second .SchemaVersion ));
872
+ }
832
873
}
833
874
834
875
Y_VERIFY_S (!CommittedLockChangeRecords.contains (lockId), " Cannot commit lock " << lockId << " more than once" );
@@ -855,7 +896,26 @@ void TDataShard::CommitLockChangeRecords(NIceDb::TNiceDb& db, ui64 lockId, ui64
855
896
LockChangeRecords.erase (it);
856
897
});
857
898
db.GetDatabase ().OnRollback ([this , lockId]() {
858
- CommittedLockChangeRecords.erase (lockId);
899
+ auto it = CommittedLockChangeRecords.find (lockId);
900
+ Y_VERIFY_S (it != CommittedLockChangeRecords.end (), " Unexpected failure to find lockId# " << lockId);
901
+
902
+ for (size_t i = 0 ; i < it->second .Count ; ++i) {
903
+ const ui64 order = it->second .Order + i;
904
+
905
+ auto cIt = ChangesQueue.find (order);
906
+ Y_VERIFY_S (cIt != ChangesQueue.end (), " Cannot find change record: " << order);
907
+
908
+ if (cIt->second .SchemaSnapshotAcquired ) {
909
+ const auto snapshotKey = TSchemaSnapshotKey (cIt->second .TableId , cIt->second .SchemaVersion );
910
+ if (const auto last = SchemaSnapshotManager.ReleaseReference (snapshotKey)) {
911
+ ScheduleRemoveSchemaSnapshot (snapshotKey);
912
+ }
913
+ }
914
+
915
+ ChangesQueue.erase (cIt);
916
+ }
917
+
918
+ CommittedLockChangeRecords.erase (it);
859
919
});
860
920
}
861
921
@@ -889,7 +949,6 @@ void TDataShard::RemoveChangeRecord(NIceDb::TNiceDb& db, ui64 order) {
889
949
890
950
auto it = ChangesQueue.find (order);
891
951
if (it == ChangesQueue.end ()) {
892
- Y_VERIFY_DEBUG_S (false , " Trying to remove non-enqueud record: " << order);
893
952
return ;
894
953
}
895
954
@@ -917,23 +976,9 @@ void TDataShard::RemoveChangeRecord(NIceDb::TNiceDb& db, ui64 order) {
917
976
ChangesQueueBytes -= record.BodySize ;
918
977
919
978
if (record.SchemaSnapshotAcquired ) {
920
- Y_ABORT_UNLESS (record.TableId );
921
- auto tableIt = TableInfos.find (record.TableId .LocalPathId );
922
-
923
- if (tableIt != TableInfos.end ()) {
924
- const auto snapshotKey = TSchemaSnapshotKey (record.TableId , record.SchemaVersion );
925
- const bool last = SchemaSnapshotManager.ReleaseReference (snapshotKey);
926
-
927
- if (last) {
928
- const auto * snapshot = SchemaSnapshotManager.FindSnapshot (snapshotKey);
929
- Y_ABORT_UNLESS (snapshot);
930
-
931
- if (snapshot->Schema ->GetTableSchemaVersion () < tableIt->second ->GetTableSchemaVersion ()) {
932
- SchemaSnapshotManager.RemoveShapshot (db, snapshotKey);
933
- }
934
- }
935
- } else {
936
- Y_DEBUG_ABORT_UNLESS (State == TShardState::PreOffline);
979
+ const auto snapshotKey = TSchemaSnapshotKey (record.TableId , record.SchemaVersion );
980
+ if (const bool last = SchemaSnapshotManager.ReleaseReference (snapshotKey)) {
981
+ ScheduleRemoveSchemaSnapshot (snapshotKey);
937
982
}
938
983
}
939
984
@@ -954,7 +999,7 @@ void TDataShard::RemoveChangeRecord(NIceDb::TNiceDb& db, ui64 order) {
954
999
CheckChangesQueueNoOverflow ();
955
1000
}
956
1001
957
- void TDataShard::EnqueueChangeRecords (TVector<IDataShardChangeCollector::TChange>&& records, ui64 cookie) {
1002
+ void TDataShard::EnqueueChangeRecords (TVector<IDataShardChangeCollector::TChange>&& records, ui64 cookie, bool afterMove ) {
958
1003
if (!records) {
959
1004
return ;
960
1005
}
@@ -974,27 +1019,24 @@ void TDataShard::EnqueueChangeRecords(TVector<IDataShardChangeCollector::TChange
974
1019
const auto now = AppData ()->TimeProvider ->Now ();
975
1020
TVector<NChangeExchange::TEvChangeExchange::TEvEnqueueRecords::TRecordInfo> forward (Reserve (records.size ()));
976
1021
for (const auto & record : records) {
977
- forward.emplace_back (record.Order , record.PathId , record.BodySize );
1022
+ auto it = ChangesQueue.find (record.Order );
1023
+ if (it == ChangesQueue.end ()) {
1024
+ Y_ABORT_UNLESS (afterMove);
1025
+ continue ;
1026
+ }
978
1027
979
- auto res = ChangesQueue.emplace (
980
- std::piecewise_construct,
981
- std::forward_as_tuple (record.Order ),
982
- std::forward_as_tuple (record, now, cookie)
983
- );
984
- if (res.second ) {
985
- ChangesList.PushBack (&res.first ->second );
1028
+ forward.emplace_back (record.Order , record.PathId , record.BodySize );
986
1029
987
- Y_ABORT_UNLESS (ChangesQueueBytes <= (Max<ui64>() - record.BodySize ));
988
- ChangesQueueBytes += record.BodySize ;
1030
+ it->second .EnqueuedAt = now;
1031
+ it->second .ReservationCookie = cookie;
1032
+ ChangesList.PushBack (&it->second );
989
1033
990
- if (record.SchemaVersion ) {
991
- res.first ->second .SchemaSnapshotAcquired = SchemaSnapshotManager.AcquireReference (
992
- TSchemaSnapshotKey (record.TableId , record.SchemaVersion ));
993
- }
994
- }
1034
+ Y_ABORT_UNLESS (ChangesQueueBytes <= (Max<ui64>() - record.BodySize ));
1035
+ ChangesQueueBytes += record.BodySize ;
995
1036
}
996
-
1037
+
997
1038
if (auto it = ChangeQueueReservations.find (cookie); it != ChangeQueueReservations.end ()) {
1039
+ Y_ABORT_UNLESS (!afterMove);
998
1040
ChangeQueueReservedCapacity -= it->second ;
999
1041
ChangeQueueReservedCapacity += records.size ();
1000
1042
}
@@ -1160,6 +1202,14 @@ bool TDataShard::LoadChangeRecords(NIceDb::TNiceDb& db, TVector<IDataShardChange
1160
1202
.SchemaVersion = schemaVersion,
1161
1203
});
1162
1204
1205
+ auto res = ChangesQueue.emplace (records.back ().Order , records.back ());
1206
+ Y_VERIFY_S (res.second , " Duplicate change record: " << records.back ().Order );
1207
+
1208
+ if (res.first ->second .SchemaVersion ) {
1209
+ res.first ->second .SchemaSnapshotAcquired = SchemaSnapshotManager.AcquireReference (
1210
+ TSchemaSnapshotKey (res.first ->second .TableId , res.first ->second .SchemaVersion ));
1211
+ }
1212
+
1163
1213
if (!rowset.Next ()) {
1164
1214
return false ;
1165
1215
}
@@ -1258,6 +1308,14 @@ bool TDataShard::LoadChangeRecordCommits(NIceDb::TNiceDb& db, TVector<IDataShard
1258
1308
});
1259
1309
entry.Count ++;
1260
1310
needSort = true ;
1311
+
1312
+ auto res = ChangesQueue.emplace (records.back ().Order , records.back ());
1313
+ Y_VERIFY_S (res.second , " Duplicate change record: " << records.back ().Order );
1314
+
1315
+ if (res.first ->second .SchemaVersion ) {
1316
+ res.first ->second .SchemaSnapshotAcquired = SchemaSnapshotManager.AcquireReference (
1317
+ TSchemaSnapshotKey (res.first ->second .TableId , res.first ->second .SchemaVersion ));
1318
+ }
1261
1319
}
1262
1320
1263
1321
LockChangeRecords.erase (lockId);
@@ -1316,6 +1374,51 @@ void TDataShard::ScheduleRemoveAbandonedLockChanges() {
1316
1374
}
1317
1375
}
1318
1376
1377
+ void TDataShard::ScheduleRemoveSchemaSnapshot (const TSchemaSnapshotKey& key) {
1378
+ Y_ABORT_UNLESS (!SchemaSnapshotManager.HasReference (key));
1379
+
1380
+ const auto * snapshot = SchemaSnapshotManager.FindSnapshot (key);
1381
+ Y_ABORT_UNLESS (snapshot);
1382
+
1383
+ auto it = TableInfos.find (key.PathId );
1384
+ if (it == TableInfos.end ()) {
1385
+ Y_DEBUG_ABORT_UNLESS (State == TShardState::PreOffline);
1386
+ return ;
1387
+ }
1388
+
1389
+ if (snapshot->Schema ->GetTableSchemaVersion () < it->second ->GetTableSchemaVersion ()) {
1390
+ bool wasEmpty = PendingSchemaSnapshotsToGc.empty ();
1391
+ PendingSchemaSnapshotsToGc.push_back (key);
1392
+ if (wasEmpty) {
1393
+ Send (SelfId (), new TEvPrivate::TEvRemoveSchemaSnapshots);
1394
+ }
1395
+ }
1396
+ }
1397
+
1398
+ void TDataShard::ScheduleRemoveAbandonedSchemaSnapshots () {
1399
+ bool wasEmpty = PendingSchemaSnapshotsToGc.empty ();
1400
+
1401
+ for (const auto & [key, snapshot] : SchemaSnapshotManager.GetSnapshots ()) {
1402
+ auto it = TableInfos.find (key.PathId );
1403
+ if (it == TableInfos.end ()) {
1404
+ Y_DEBUG_ABORT_UNLESS (State == TShardState::PreOffline);
1405
+ break ;
1406
+ }
1407
+ if (SchemaSnapshotManager.HasReference (key)) {
1408
+ continue ;
1409
+ }
1410
+ if (snapshot.Schema ->GetTableSchemaVersion () >= it->second ->GetTableSchemaVersion ()) {
1411
+ continue ;
1412
+ }
1413
+
1414
+ PendingSchemaSnapshotsToGc.push_back (key);
1415
+ }
1416
+
1417
+ if (wasEmpty && !PendingSchemaSnapshotsToGc.empty ()) {
1418
+ Send (SelfId (), new TEvPrivate::TEvRemoveSchemaSnapshots);
1419
+ }
1420
+ }
1421
+
1319
1422
void TDataShard::PersistSchemeTxResult (NIceDb::TNiceDb &db, const TSchemaOperation &op) {
1320
1423
db.Table <Schema::SchemaOperations>().Key (op.TxId ).Update (
1321
1424
NIceDb::TUpdate<Schema::SchemaOperations::Success>(op.Success ),
@@ -1529,8 +1632,18 @@ void TDataShard::AddSchemaSnapshot(const TPathId& pathId, ui64 tableSchemaVersio
1529
1632
Y_ABORT_UNLESS (TableInfos.contains (pathId.LocalPathId ));
1530
1633
auto tableInfo = TableInfos[pathId.LocalPathId ];
1531
1634
1532
- const auto key = TSchemaSnapshotKey (pathId. OwnerId , pathId. LocalPathId , tableSchemaVersion);
1635
+ const auto key = TSchemaSnapshotKey (pathId, tableSchemaVersion);
1533
1636
SchemaSnapshotManager.AddSnapshot (txc.DB , key, TSchemaSnapshot (tableInfo, step, txId));
1637
+
1638
+ const auto & snapshots = SchemaSnapshotManager.GetSnapshots ();
1639
+ for (auto it = snapshots.lower_bound (TSchemaSnapshotKey (pathId, 1 )); it != snapshots.end (); ++it) {
1640
+ if (it->first == key) {
1641
+ break ;
1642
+ }
1643
+ if (!SchemaSnapshotManager.HasReference (it->first )) {
1644
+ ScheduleRemoveSchemaSnapshot (it->first );
1645
+ }
1646
+ }
1534
1647
}
1535
1648
1536
1649
void TDataShard::PersistLastLoanTableTid (NIceDb::TNiceDb& db, ui32 localTid) {
0 commit comments