Skip to content

Commit

Permalink
Merge 8b52a2f into 24479f4
Browse files Browse the repository at this point in the history
  • Loading branch information
FloatingCrowbar authored Feb 9, 2024
2 parents 24479f4 + 8b52a2f commit 3ad495b
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 35 deletions.
5 changes: 3 additions & 2 deletions ydb/core/persqueue/partition_sourcemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ bool TPartitionSourceManager::HasParents() const {

TPartitionSourceManager::TModificationBatch::TModificationBatch(TPartitionSourceManager& manager, ESourceIdFormat format)
: Manager(manager)
, Node(Manager.GetPartitionNode())
, Node(Manager.GetPartitionNode())
, SourceIdWriter(format)
, HeartbeatEmitter(Manager.Partition.SourceIdStorage) {
}
Expand Down Expand Up @@ -104,6 +104,7 @@ TPartitionSourceManager& TPartitionSourceManager::TModificationBatch::GetManager
TPartitionSourceManager::TSourceInfo Convert(TSourceIdInfo value) {
TPartitionSourceManager::TSourceInfo result(value.State);
result.SeqNo = value.SeqNo;
result.MinSeqNo = value.MinSeqNo;
result.Offset = value.Offset;
result.Explicit = value.Explicit;
result.WriteTimestamp = value.WriteTimestamp;
Expand Down Expand Up @@ -147,7 +148,7 @@ std::optional<ui64> TPartitionSourceManager::TSourceManager::UpdatedSeqNo() cons

void TPartitionSourceManager::TSourceManager::Update(ui64 seqNo, ui64 offset, TInstant timestamp) {
if (InMemory == MemoryStorage().end()) {
Batch.SourceIdWriter.RegisterSourceId(SourceId, seqNo, offset, timestamp);
Batch.SourceIdWriter.RegisterSourceId(SourceId, seqNo, seqNo, offset, timestamp);
} else {
Batch.SourceIdWriter.RegisterSourceId(SourceId, InMemory->second.Updated(seqNo, offset, timestamp));
}
Expand Down
1 change: 1 addition & 0 deletions ydb/core/persqueue/partition_sourcemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class TPartitionSourceManager {

TSourceIdInfo::EState State;
ui64 SeqNo = 0;
ui64 MinSeqNo = 0;
ui64 Offset = 0;
bool Explicit = false;
TInstant WriteTimestamp;
Expand Down
20 changes: 10 additions & 10 deletions ydb/core/persqueue/partition_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,12 @@ void TPartition::ProcessReserveRequests(const TActorContext& ctx) {

const ui64 currentSize = ReservedSize + WriteInflightSize + WriteCycleSize;
if (currentSize != 0 && currentSize + size > maxWriteInflightSize) {
LOG_DEBUG_S(ctx, NKikimrServices::PERSQUEUE, "Reserve processing: maxWriteInflightSize riched. Partition: " << Partition);
LOG_DEBUG_S(ctx, NKikimrServices::PERSQUEUE, "Reserve processing: maxWriteInflightSize riched. Partition: " << Partition);
break;
}

if (WaitingForSubDomainQuota(ctx, currentSize)) {
LOG_DEBUG_S(ctx, NKikimrServices::PERSQUEUE, "Reserve processing: SubDomainOutOfSpace. Partition: " << Partition);
LOG_DEBUG_S(ctx, NKikimrServices::PERSQUEUE, "Reserve processing: SubDomainOutOfSpace. Partition: " << Partition);
break;
}

Expand Down Expand Up @@ -327,7 +327,7 @@ void TPartition::AnswerCurrentWrites(const TActorContext& ctx) {
if (it == SourceIdStorage.GetInMemorySourceIds().end()) {
Y_ABORT_UNLESS(!writeResponse.Msg.HeartbeatVersion);
TabletCounters.Cumulative()[COUNTER_PQ_SID_CREATED].Increment(1);
SourceIdStorage.RegisterSourceId(s, seqNo, offset, CurrentTimestamp);
SourceIdStorage.RegisterSourceId(s, seqNo, 0, offset, CurrentTimestamp);
} else if (const auto& hbVersion = writeResponse.Msg.HeartbeatVersion) {
SourceIdStorage.RegisterSourceId(s, it->second.Updated(
seqNo, offset, CurrentTimestamp, THeartbeat{*hbVersion, writeResponse.Msg.Data}
Expand Down Expand Up @@ -378,7 +378,7 @@ void TPartition::AnswerCurrentWrites(const TActorContext& ctx) {
}

Y_ABORT_UNLESS(body.AssignedOffset);
SourceIdStorage.RegisterSourceId(body.SourceId, body.SeqNo, *body.AssignedOffset, CurrentTimestamp, std::move(keyRange));
SourceIdStorage.RegisterSourceId(body.SourceId, body.SeqNo, 0, *body.AssignedOffset, CurrentTimestamp, std::move(keyRange));
ReplyOk(ctx, response.GetCookie());
} else if (response.IsDeregisterMessageGroup()) {
const auto& body = response.GetDeregisterMessageGroup().Body;
Expand All @@ -399,7 +399,7 @@ void TPartition::AnswerCurrentWrites(const TActorContext& ctx) {
}

Y_ABORT_UNLESS(body.AssignedOffset);
SourceIdStorage.RegisterSourceId(body.SourceId, body.SeqNo, *body.AssignedOffset, CurrentTimestamp, std::move(keyRange), true);
SourceIdStorage.RegisterSourceId(body.SourceId, body.SeqNo, 0, *body.AssignedOffset, CurrentTimestamp, std::move(keyRange), true);
}

ReplyOk(ctx, response.GetCookie());
Expand Down Expand Up @@ -727,7 +727,7 @@ void TPartition::HandleOnWrite(TEvPQ::TEvDeregisterMessageGroup::TPtr& ev, const
return ReplyError(ctx, ev->Get()->Cookie, NPersQueue::NErrorCode::SOURCEID_DELETED,
"SourceId doesn't exist");
}

EmplaceRequest(TDeregisterMessageGroupMsg(*ev->Get()), ctx);
}

Expand Down Expand Up @@ -836,7 +836,7 @@ TPartition::ProcessResult TPartition::ProcessRequest(TRegisterMessageGroupMsg& m
}

body.AssignedOffset = parameters.CurOffset;
parameters.SourceIdBatch.RegisterSourceId(body.SourceId, body.SeqNo, parameters.CurOffset, CurrentTimestamp, std::move(keyRange));
parameters.SourceIdBatch.RegisterSourceId(body.SourceId, body.SeqNo, 0, parameters.CurOffset, CurrentTimestamp, std::move(keyRange));

return ProcessResult::Continue;
}
Expand All @@ -859,7 +859,7 @@ TPartition::ProcessResult TPartition::ProcessRequest(TSplitMessageGroupMsg& msg,
}

body.AssignedOffset = parameters.CurOffset;
parameters.SourceIdBatch.RegisterSourceId(body.SourceId, body.SeqNo, parameters.CurOffset, CurrentTimestamp, std::move(keyRange), true);
parameters.SourceIdBatch.RegisterSourceId(body.SourceId, body.SeqNo, 0, parameters.CurOffset, CurrentTimestamp, std::move(keyRange), true);
}

return ProcessResult::Continue;
Expand Down Expand Up @@ -1519,7 +1519,7 @@ void TPartition::HandleWrites(const TActorContext& ctx) {
THolder<TEvKeyValue::TEvRequest> request(new TEvKeyValue::TEvRequest);

Y_ABORT_UNLESS(Head.PackedSize + NewHead.PackedSize <= 2 * MaxSizeCheck);

TInstant now = ctx.Now();
WriteCycleStartTime = now;

Expand Down Expand Up @@ -1592,7 +1592,7 @@ bool TPartition::WaitingForSubDomainQuota(const TActorContext& ctx, const ui64 w

void TPartition::WriteBlobWithQuota(const TActorContext& /*ctx*/, THolder<TEvKeyValue::TEvRequest>&& request) {
PQ_LOG_T("TPartition::WriteBlobWithQuota.");

// Request quota and write blob.
// Mirrored topics are not quoted in local dc.
const bool skip = !IsQuotingEnabled() || TopicWriteQuotaResourcePath.empty();
Expand Down
2 changes: 1 addition & 1 deletion ydb/core/persqueue/pq_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1500,7 +1500,7 @@ void TPersQueue::AddCmdWriteConfig(TEvKeyValue::TEvRequest* request,
keyRange = TPartitionKeyRange::Parse(mg.GetKeyRange());
}

sourceIdWriter.RegisterSourceId(mg.GetId(), 0, 0, ctx.Now(), std::move(keyRange));
sourceIdWriter.RegisterSourceId(mg.GetId(), 0, 0, 0, ctx.Now(), std::move(keyRange));
}

for (const auto& partition : cfg.GetPartitions()) {
Expand Down
14 changes: 11 additions & 3 deletions ydb/core/persqueue/sourceid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,25 +101,28 @@ void THeartbeatProcessor::ForgetSourceId(const TString& sourceId) {
SourceIdsWithHeartbeat.erase(sourceId);
}

TSourceIdInfo::TSourceIdInfo(ui64 seqNo, ui64 offset, TInstant createTs)
TSourceIdInfo::TSourceIdInfo(ui64 seqNo, ui64 minSeqNo, ui64 offset, TInstant createTs)
: SeqNo(seqNo)
, MinSeqNo(minSeqNo)
, Offset(offset)
, WriteTimestamp(createTs)
, CreateTimestamp(createTs)
{
}

TSourceIdInfo::TSourceIdInfo(ui64 seqNo, ui64 offset, TInstant createTs, THeartbeat&& heartbeat)
TSourceIdInfo::TSourceIdInfo(ui64 seqNo, ui64 minSeqNo, ui64 offset, TInstant createTs, THeartbeat&& heartbeat)
: SeqNo(seqNo)
, MinSeqNo(minSeqNo)
, Offset(offset)
, WriteTimestamp(createTs)
, CreateTimestamp(createTs)
, LastHeartbeat(std::move(heartbeat))
{
}

TSourceIdInfo::TSourceIdInfo(ui64 seqNo, ui64 offset, TInstant createTs, TMaybe<TPartitionKeyRange>&& keyRange, bool isInSplit)
TSourceIdInfo::TSourceIdInfo(ui64 seqNo, ui64 minSeqNo, ui64 offset, TInstant createTs, TMaybe<TPartitionKeyRange>&& keyRange, bool isInSplit)
: SeqNo(seqNo)
, MinSeqNo(minSeqNo)
, Offset(offset)
, CreateTimestamp(createTs)
, Explicit(true)
Expand All @@ -133,6 +136,9 @@ TSourceIdInfo::TSourceIdInfo(ui64 seqNo, ui64 offset, TInstant createTs, TMaybe<
TSourceIdInfo TSourceIdInfo::Updated(ui64 seqNo, ui64 offset, TInstant writeTs) const {
auto copy = *this;
copy.SeqNo = seqNo;
if (copy.MinSeqNo == 0 || copy.MinSeqNo > seqNo) {
copy.MinSeqNo = seqNo;
}
copy.Offset = offset;
copy.WriteTimestamp = writeTs;

Expand Down Expand Up @@ -178,6 +184,7 @@ void TSourceIdInfo::Serialize(TBuffer& data) const {
TSourceIdInfo TSourceIdInfo::Parse(const NKikimrPQ::TMessageGroupInfo& proto) {
TSourceIdInfo result;
result.SeqNo = proto.GetSeqNo();
result.MinSeqNo = proto.GetMinSeqNo();
result.Offset = proto.GetOffset();
result.WriteTimestamp = TInstant::FromValue(proto.GetWriteTimestamp());
result.CreateTimestamp = TInstant::FromValue(proto.GetCreateTimestamp());
Expand All @@ -197,6 +204,7 @@ TSourceIdInfo TSourceIdInfo::Parse(const NKikimrPQ::TMessageGroupInfo& proto) {

void TSourceIdInfo::Serialize(NKikimrPQ::TMessageGroupInfo& proto) const {
proto.SetSeqNo(SeqNo);
proto.SetMinSeqNo(MinSeqNo);
proto.SetOffset(Offset);
proto.SetWriteTimestamp(WriteTimestamp.GetValue());
proto.SetCreateTimestamp(CreateTimestamp.GetValue());
Expand Down
7 changes: 4 additions & 3 deletions ydb/core/persqueue/sourceid.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct TSourceIdInfo {
};

ui64 SeqNo = 0;
ui64 MinSeqNo = 0;
ui64 Offset = 0;
TInstant WriteTimestamp;
TInstant CreateTimestamp;
Expand All @@ -33,9 +34,9 @@ struct TSourceIdInfo {
EState State = EState::Registered;

TSourceIdInfo() = default;
TSourceIdInfo(ui64 seqNo, ui64 offset, TInstant createTs);
TSourceIdInfo(ui64 seqNo, ui64 offset, TInstant createTs, THeartbeat&& heartbeat);
TSourceIdInfo(ui64 seqNo, ui64 offset, TInstant createTs, TMaybe<TPartitionKeyRange>&& keyRange, bool isInSplit = false);
TSourceIdInfo(ui64 seqNo, ui64 minSeqNo, ui64 offset, TInstant createTs);
TSourceIdInfo(ui64 seqNo, ui64 minSeqNo, ui64 offset, TInstant createTs, THeartbeat&& heartbeat);
TSourceIdInfo(ui64 seqNo, ui64 minSeqNo, ui64 offset, TInstant createTs, TMaybe<TPartitionKeyRange>&& keyRange, bool isInSplit = false);

TSourceIdInfo Updated(ui64 seqNo, ui64 offset, TInstant writeTs) const;
TSourceIdInfo Updated(ui64 seqNo, ui64 offset, TInstant writeTs, THeartbeat&& heartbeat) const;
Expand Down
64 changes: 48 additions & 16 deletions ydb/core/persqueue/ut/sourceid_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
TSourceIdWriter writer(ESourceIdFormat::Raw);

const auto sourceId = TestSourceId(1);
const auto sourceIdInfo = TSourceIdInfo(1, 10, TInstant::Seconds(100));
const auto sourceIdInfo = TSourceIdInfo(1, 0, 10, TInstant::Seconds(100));

writer.RegisterSourceId(sourceId, sourceIdInfo);
UNIT_ASSERT_VALUES_EQUAL(writer.GetSourceIdsToWrite().size(), 1);
Expand All @@ -35,7 +35,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
}

const auto anotherSourceId = TestSourceId(2);
const auto anotherSourceIdInfo = TSourceIdInfo(2, 20, TInstant::Seconds(200));
const auto anotherSourceIdInfo = TSourceIdInfo(2, 0, 20, TInstant::Seconds(200));
UNIT_ASSERT_VALUES_UNEQUAL(sourceIdInfo, anotherSourceIdInfo);

{
Expand All @@ -47,7 +47,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
Y_UNIT_TEST(SourceIdWriterClean) {
TSourceIdWriter writer(ESourceIdFormat::Raw);

writer.RegisterSourceId(TestSourceId(), 1, 10, TInstant::Seconds(100));
writer.RegisterSourceId(TestSourceId(), 1, 0, 10, TInstant::Seconds(100));
UNIT_ASSERT_VALUES_EQUAL(writer.GetSourceIdsToWrite().size(), 1);

writer.Clear();
Expand All @@ -60,7 +60,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
auto expectedRequest = MakeHolder<TEvKeyValue::TEvRequest>();

const auto sourceId = TestSourceId(1);
const auto sourceIdInfo = TSourceIdInfo(1, 10, TInstant::Seconds(100));
const auto sourceIdInfo = TSourceIdInfo(1, 1, 10, TInstant::Seconds(100));
writer.RegisterSourceId(sourceId, sourceIdInfo);
UNIT_ASSERT_VALUES_EQUAL(writer.GetSourceIdsToWrite().size(), 1);
{
Expand All @@ -78,7 +78,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
}

const auto anotherSourceId = TestSourceId(2);
const auto anotherSourceIdInfo = TSourceIdInfo(2, 20, TInstant::Seconds(200));
const auto anotherSourceIdInfo = TSourceIdInfo(2, 0, 20, TInstant::Seconds(200));
writer.RegisterSourceId(anotherSourceId, anotherSourceIdInfo);
UNIT_ASSERT_VALUES_EQUAL(writer.GetSourceIdsToWrite().size(), 2);
{
Expand All @@ -102,9 +102,9 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
TSourceIdStorage storage;

const auto sourceId = TestSourceId(1);
const auto sourceIdInfo = TSourceIdInfo(1, 10, TInstant::Seconds(100));
const auto sourceIdInfo = TSourceIdInfo(1, 0, 10, TInstant::Seconds(100));
const auto anotherSourceId = TestSourceId(2);
const auto anotherSourceIdInfo = TSourceIdInfo(2, 20, TInstant::Seconds(200));
const auto anotherSourceIdInfo = TSourceIdInfo(2, 0, 20, TInstant::Seconds(200));

storage.RegisterSourceId(sourceId, sourceIdInfo);
UNIT_ASSERT_VALUES_EQUAL(storage.GetInMemorySourceIds().size(), 1);
Expand All @@ -130,7 +130,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {

void SourceIdStorageParseAndAdd(TKeyPrefix::EMark mark, ESourceIdFormat format) {
const auto sourceId = TestSourceId();
const auto sourceIdInfo = TSourceIdInfo(1, 10, TInstant::Seconds(100));
const auto sourceIdInfo = TSourceIdInfo(1, 1, 10, TInstant::Seconds(100));

TKeyPrefix ikey(TKeyPrefix::TypeInfo, TPartitionId(TestPartition), mark);
TBuffer idata;
Expand Down Expand Up @@ -162,20 +162,20 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
TSourceIdStorage storage;

const auto sourceId = TestSourceId(1);
storage.RegisterSourceId(sourceId, 1, 10, TInstant::Seconds(100));
storage.RegisterSourceId(sourceId, 1, 0, 10, TInstant::Seconds(100));
{
auto ds = storage.MinAvailableTimestamp(now);
UNIT_ASSERT_VALUES_EQUAL(ds, TInstant::Seconds(100));
}

const auto anotherSourceId = TestSourceId(2);
storage.RegisterSourceId(anotherSourceId, 2, 20, TInstant::Seconds(200));
storage.RegisterSourceId(anotherSourceId, 2, 0, 20, TInstant::Seconds(200));
{
auto ds = storage.MinAvailableTimestamp(now);
UNIT_ASSERT_VALUES_EQUAL(ds, TInstant::Seconds(100));
}

storage.RegisterSourceId(sourceId, 3, 30, TInstant::Seconds(300));
storage.RegisterSourceId(sourceId, 3, 0, 30, TInstant::Seconds(300));
{
auto ds = storage.MinAvailableTimestamp(now);
UNIT_ASSERT_VALUES_EQUAL(ds, TInstant::Seconds(200));
Expand All @@ -185,7 +185,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
Y_UNIT_TEST(SourceIdStorageTestClean) {
TSourceIdStorage storage;
for (ui64 i = 1; i <= 10000; ++i) {
storage.RegisterSourceId(TestSourceId(i), i, i, TInstant::Seconds(10 * i));
storage.RegisterSourceId(TestSourceId(i), i, 0, i, TInstant::Seconds(10 * i));
}

NKikimrPQ::TPartitionConfig config;
Expand Down Expand Up @@ -226,7 +226,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
Y_UNIT_TEST(SourceIdStorageDeleteByMaxCount) {
TSourceIdStorage storage;
for (ui64 i = 1; i <= 10000; ++i) {
storage.RegisterSourceId(TestSourceId(i), i, i, TInstant::Seconds(10 * i));
storage.RegisterSourceId(TestSourceId(i), i, 0, i, TInstant::Seconds(10 * i));
}

NKikimrPQ::TPartitionConfig config;
Expand Down Expand Up @@ -258,7 +258,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
Y_UNIT_TEST(SourceIdStorageComplexDelete) {
TSourceIdStorage storage;
for (ui64 i = 1; i <= 10000 + 1; ++i) { // add 10000 + one extra sources
storage.RegisterSourceId(TestSourceId(i), i, i, TInstant::Seconds(10 * i));
storage.RegisterSourceId(TestSourceId(i), i, 1, i , TInstant::Seconds(10 * i));
}

NKikimrPQ::TPartitionConfig config;
Expand Down Expand Up @@ -297,7 +297,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
const auto sourceId = TestSourceId(i);
const auto owner = TestOwner(sourceId);

storage.RegisterSourceId(sourceId, i, i, TInstant::Hours(i));
storage.RegisterSourceId(sourceId, i, 0, i, TInstant::Hours(i));
storage.RegisterSourceIdOwner(sourceId, owner);
owners[owner];
}
Expand All @@ -324,7 +324,7 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
}

inline static TSourceIdInfo MakeExplicitSourceIdInfo(ui64 offset, const TMaybe<THeartbeat>& heartbeat = Nothing()) {
auto info = TSourceIdInfo(0, offset, TInstant::Now());
auto info = TSourceIdInfo(0, 0, offset, TInstant::Now());

info.Explicit = true;
if (heartbeat) {
Expand Down Expand Up @@ -460,6 +460,38 @@ Y_UNIT_TEST_SUITE(TSourceIdTests) {
}
}

Y_UNIT_TEST(SourceIdMinSeqNo) {
TSourceIdStorage storage;

const auto sourceId = TestSourceId(1);
const auto sourceIdInfo = TSourceIdInfo(1, 0, 10, TInstant::Seconds(100));
const auto anotherSourceId = TestSourceId(2);
const auto anotherSourceIdInfo = TSourceIdInfo(2, 1, 20, TInstant::Seconds(200));

storage.RegisterSourceId(sourceId, sourceIdInfo);
storage.RegisterSourceId(anotherSourceId, anotherSourceIdInfo);
{
auto it = storage.GetInMemorySourceIds().find(anotherSourceId);
UNIT_ASSERT_VALUES_EQUAL(it->second.MinSeqNo, 1);
}

storage.RegisterSourceId(sourceId, sourceIdInfo.Updated(2, 11, TInstant::Seconds(100)));
{
auto it = storage.GetInMemorySourceIds().find(sourceId);
UNIT_ASSERT_VALUES_EQUAL(it->second.MinSeqNo, 2);
}
storage.RegisterSourceId(sourceId, sourceIdInfo.Updated(1, 12, TInstant::Seconds(100)));
{
auto it = storage.GetInMemorySourceIds().find(sourceId);
UNIT_ASSERT_VALUES_EQUAL(it->second.MinSeqNo, 1);
}
storage.RegisterSourceId(anotherSourceId, anotherSourceIdInfo.Updated(3, 12, TInstant::Seconds(100)));
{
auto it = storage.GetInMemorySourceIds().find(anotherSourceId);
UNIT_ASSERT_VALUES_EQUAL(it->second.MinSeqNo, 1);
}
}

} // TSourceIdTests

} // namespace NKikimr::NPQ
1 change: 1 addition & 0 deletions ydb/core/protos/pqconfig.proto
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ message TMessageGroupInfo {
}

optional uint64 SeqNo = 1;
optional uint64 MinSeqNo = 9;
optional uint64 Offset = 2;
optional uint64 WriteTimestamp = 3; // TInstant::TValue
optional uint64 CreateTimestamp = 4; // TInstant::TValue
Expand Down

0 comments on commit 3ad495b

Please sign in to comment.