Skip to content

Commit f28e3a5

Browse files
committed
issue-6608: Implement quota usage aggregation across shards
1 parent 90fadfc commit f28e3a5

6 files changed

Lines changed: 122 additions & 0 deletions

File tree

cloud/filestore/libs/storage/service/service_ut_sharding.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,74 @@ Y_UNIT_TEST_SUITE(TStorageServiceShardingTest)
620620
}
621621
}
622622

623+
SERVICE_TEST(ShouldAggregateQuotaUsageAcrossShards)
624+
{
625+
TShardedFileSystemConfig fsConfig;
626+
CREATE_ENV_AND_SHARDED_FILESYSTEM();
627+
628+
{
629+
NProtoPrivate::TSetQuotaRequest request;
630+
request.SetFileSystemId(fsConfig.FsId);
631+
request.SetQuotaId(42);
632+
request.SetMaxBytes(1_GB);
633+
request.SetMaxNodes(100);
634+
635+
TString buf;
636+
google::protobuf::util::MessageToJsonString(request, &buf);
637+
service.ExecuteAction("setquota", buf);
638+
}
639+
640+
auto headers = service.InitSession(fsConfig.FsId, "client");
641+
642+
// attach the quota to a directory on main - files are regular nodes,
643+
// so main auto-routes their creation into shards (round-robin) and
644+
// forwards the inherited QuotaId along with each one; the directory
645+
// itself stays on main and its own attach bumps main's own local
646+
// usage by 1
647+
auto dirId = service
648+
.CreateNode(
649+
headers,
650+
TCreateNodeArgs::Directory(RootNodeId, "dir"))
651+
->Record.GetNode()
652+
.GetId();
653+
service.SetNodeAttr(
654+
headers,
655+
fsConfig.FsId,
656+
TSetNodeAttrArgs(dirId).SetQuotaId(42));
657+
658+
constexpr ui32 fileCount = 4;
659+
for (ui32 i = 0; i < fileCount; ++i) {
660+
service.CreateNode(
661+
headers,
662+
TCreateNodeArgs::File(dirId, "file" + ToString(i)));
663+
}
664+
665+
// each shard should have received at least one of the files -
666+
// otherwise this test wouldn't actually be exercising cross-shard
667+
// aggregation
668+
for (const auto& shardId: fsConfig.ShardIds()) {
669+
const auto stats = GetStorageStats(service, shardId);
670+
const auto& usages = stats.GetStats().GetQuotaUsages();
671+
UNIT_ASSERT_VALUES_EQUAL_C(1, usages.size(), shardId);
672+
UNIT_ASSERT_VALUES_EQUAL_C(42u, usages[0].GetQuotaId(), shardId);
673+
UNIT_ASSERT_C(usages[0].GetUsedNodes() > 0, shardId);
674+
}
675+
676+
// forcing main to fan out and aggregate should sum main's own local
677+
// usage (the directory attach point) and both shards' contributions
678+
// (the files) together
679+
const auto aggregate = GetStorageStats(
680+
service,
681+
fsConfig.FsId,
682+
0 /* cacheTTL */,
683+
NProtoPrivate::STATS_REQUEST_MODE_FORCE_FETCH_SHARDS);
684+
const auto& usages = aggregate.GetStats().GetQuotaUsages();
685+
UNIT_ASSERT_VALUES_EQUAL(1, usages.size());
686+
UNIT_ASSERT_VALUES_EQUAL(42u, usages[0].GetQuotaId());
687+
UNIT_ASSERT_VALUES_EQUAL(1 + fileCount, usages[0].GetUsedNodes());
688+
UNIT_ASSERT_VALUES_EQUAL(0u, usages[0].GetUsedBytes());
689+
}
690+
623691
SERVICE_TEST(ShouldCheckForShardsInAdapterModeUponSessionCreationInShards)
624692
{
625693
//

cloud/filestore/libs/storage/tablet/tablet_actor_counters.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,31 @@ using namespace NMetrics;
1717

1818
namespace {
1919

20+
////////////////////////////////////////////////////////////////////////////////
21+
22+
void MergeQuotaUsages(
23+
NProtoPrivate::TStorageStats& dst,
24+
const NProtoPrivate::TStorageStats& src)
25+
{
26+
for (const auto& srcUsage: src.GetQuotaUsages()) {
27+
NProtoPrivate::TQuotaUsage* dstUsage = nullptr;
28+
for (auto& usage: *dst.MutableQuotaUsages()) {
29+
if (usage.GetQuotaId() == srcUsage.GetQuotaId()) {
30+
dstUsage = &usage;
31+
break;
32+
}
33+
}
34+
if (!dstUsage) {
35+
dstUsage = dst.AddQuotaUsages();
36+
dstUsage->SetQuotaId(srcUsage.GetQuotaId());
37+
}
38+
dstUsage->SetUsedBytes(
39+
dstUsage->GetUsedBytes() + srcUsage.GetUsedBytes());
40+
dstUsage->SetUsedNodes(
41+
dstUsage->GetUsedNodes() + srcUsage.GetUsedNodes());
42+
}
43+
}
44+
2045
////////////////////////////////////////////////////////////////////////////////
2146
// TAggregateStatsActor always replies with
2247
// TAggregateStatsCompleted to a TIndexTabletActor that created the actor.
@@ -230,6 +255,8 @@ void TAggregateStatsActor::HandleGetStorageStatsResponse(
230255
dst.SetSevenBytesHandlesCount(
231256
dst.GetSevenBytesHandlesCount() + src.GetSevenBytesHandlesCount());
232257

258+
MergeQuotaUsages(dst, src);
259+
233260
LOG_DEBUG(
234261
ctx,
235262
TFileStoreComponents::TABLET_WORKER,
@@ -810,6 +837,13 @@ void TIndexTabletActor::FillSelfStorageStats(
810837
stats->SetUnconfirmedDataCount(
811838
UnconfirmedData.size() + UnconfirmedDataInProgress.size());
812839
stats->SetConfirmedDataCount(ConfirmedData.size());
840+
841+
for (const auto& usage: GetQuotaUsages()) {
842+
auto* proto = stats->AddQuotaUsages();
843+
proto->SetQuotaId(usage.QuotaId);
844+
proto->SetUsedBytes(usage.UsedBytes);
845+
proto->SetUsedNodes(usage.UsedNodes);
846+
}
813847
}
814848

815849
void TIndexTabletActor::HandleGetStorageStats(

cloud/filestore/libs/storage/tablet/tablet_actor_monitoring.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,15 +1356,24 @@ void TIndexTabletActor::RenderHttpInfo_QuotasTab(IOutputStream& out)
13561356
TABLEH() { out << "QuotaId"; }
13571357
TABLEH() { out << "MaxBytes"; }
13581358
TABLEH() { out << "MaxNodes"; }
1359+
TABLEH() { out << "UsedBytes"; }
1360+
TABLEH() { out << "UsedNodes"; }
13591361
TABLEH() { out << "CreatedAt"; }
13601362
}
13611363
}
13621364

13631365
for (const auto& quota: quotas) {
1366+
const auto* usage = FindQuotaUsage(quota.GetQuotaId());
13641367
TABLER() {
13651368
TABLED() { out << quota.GetQuotaId(); }
13661369
TABLED() { out << FormatByteSize(quota.GetMaxBytes()); }
13671370
TABLED() { out << quota.GetMaxNodes(); }
1371+
TABLED() {
1372+
out << (usage
1373+
? FormatByteSize(usage->UsedBytes)
1374+
: FormatByteSize(0));
1375+
}
1376+
TABLED() { out << (usage ? usage->UsedNodes : 0); }
13681377
TABLED() {
13691378
out << TInstant::MicroSeconds(
13701379
quota.GetCreationTimestampUs());

cloud/filestore/libs/storage/tablet/tablet_state.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,8 @@ FILESTORE_DUPCACHE_REQUESTS(FILESTORE_DECLARE_DUPCACHE)
13701370

13711371
void LoadQuotaUsages(const TVector<TQuotaUsage>& usages);
13721372

1373+
const TQuotaUsage* FindQuotaUsage(ui32 quotaId) const;
1374+
13731375
TVector<TQuotaUsage> GetQuotaUsages() const;
13741376

13751377
//

cloud/filestore/libs/storage/tablet/tablet_state_quotas.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ void TIndexTabletState::LoadQuotaUsages(const TVector<TQuotaUsage>& usages)
6363
}
6464
}
6565

66+
const TQuotaUsage* TIndexTabletState::FindQuotaUsage(ui32 quotaId) const
67+
{
68+
return Impl->Quotas.FindUsage(quotaId);
69+
}
70+
6671
TVector<TQuotaUsage> TIndexTabletState::GetQuotaUsages() const
6772
{
6873
return Impl->Quotas.GetUsages();

cloud/filestore/private/api/protos/tablet.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ message TStorageStats
176176
repeated TNodeStats NodeStats = 7001;
177177

178178
repeated TNodeLatencyStats LatencyStats = 8001;
179+
180+
// aggregated usage per quota, summed across this tablet and (once
181+
// fanned out and merged by TAggregateStatsActor) every shard
182+
repeated TQuotaUsage QuotaUsages = 9001;
179183
}
180184

181185
enum EStatsRequestMode

0 commit comments

Comments
 (0)