Skip to content

Commit

Permalink
issue-95: operations that can potentially cause Truncate should not b…
Browse files Browse the repository at this point in the history
…e allowed until compaction map gets fully loaded (#766)

* issue-95: operations that can potentially cause Truncate should not be allowed until compaction map gets fully loaded

* issue-95: operations that can potentially cause Truncate should not be allowed until compaction map gets fully loaded - fixed some uts
  • Loading branch information
qkrorlqr authored Mar 18, 2024
1 parent 68ce0e6 commit ad0d642
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 1 deletion.
11 changes: 11 additions & 0 deletions cloud/filestore/libs/storage/tablet/tablet_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,17 @@ void TIndexTabletActor::ResetThrottlingPolicy()

////////////////////////////////////////////////////////////////////////////////

NProto::TError TIndexTabletActor::IsDataOperationAllowed() const
{
if (!CompactionStateLoadStatus.Finished) {
return MakeError(E_REJECTED, "compaction state not loaded yet");
}

return {};
}

////////////////////////////////////////////////////////////////////////////////

void TIndexTabletActor::HandleWakeup(
const TEvents::TEvWakeup::TPtr& ev,
const TActorContext& ctx)
Expand Down
2 changes: 2 additions & 0 deletions cloud/filestore/libs/storage/tablet/tablet_actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ class TIndexTabletActor final
const typename TMethod::TRequest::TPtr& ev,
const NActors::TActorContext& ctx);

NProto::TError IsDataOperationAllowed() const;

void HandleWakeup(
const NActors::TEvents::TEvWakeup::TPtr& ev,
const NActors::TActorContext& ctx);
Expand Down
10 changes: 10 additions & 0 deletions cloud/filestore/libs/storage/tablet/tablet_actor_allocatedata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ void TIndexTabletActor::HandleAllocateData(
const TEvService::TEvAllocateDataRequest::TPtr& ev,
const TActorContext& ctx)
{
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvService::TEvAllocateDataResponse>(
std::move(error)));

return;
}

auto validator = [&] (const NProto::TAllocateDataRequest& request) {
return ValidateRequest(request, GetBlockSize());
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ void TIndexTabletActor::HandleDeleteCheckpoint(
const TEvIndexTabletPrivate::TEvDeleteCheckpointRequest::TPtr& ev,
const TActorContext& ctx)
{
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvIndexTabletPrivate::TEvDeleteCheckpointResponse>(
std::move(error)));

return;
}

auto* msg = ev->Get();

LOG_DEBUG(ctx, TFileStoreComponents::TABLET,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,16 @@ void TIndexTabletActor::HandleDestroyCheckpoint(
const TEvService::TEvDestroyCheckpointRequest::TPtr& ev,
const TActorContext& ctx)
{
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvService::TEvDestroyCheckpointResponse>(
std::move(error)));

return;
}

auto* msg = ev->Get();

const auto& checkpointId = msg->Record.GetCheckpointId();
Expand Down
10 changes: 10 additions & 0 deletions cloud/filestore/libs/storage/tablet/tablet_actor_destroyhandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ void TIndexTabletActor::HandleDestroyHandle(
const TEvService::TEvDestroyHandleRequest::TPtr& ev,
const TActorContext& ctx)
{
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvService::TEvDestroyHandleResponse>(
std::move(error)));

return;
}

if (!AcceptRequest<TEvService::TDestroyHandleMethod>(ev, ctx)) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ void TIndexTabletActor::HandleDestroySession(
const TEvIndexTablet::TEvDestroySessionRequest::TPtr& ev,
const TActorContext& ctx)
{
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvIndexTablet::TEvDestroySessionResponse>(
std::move(error)));

return;
}

auto* msg = ev->Get();

const auto& clientId = GetClientId(msg->Record);
Expand Down
16 changes: 15 additions & 1 deletion cloud/filestore/libs/storage/tablet/tablet_actor_setnodeattr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,28 @@ void TIndexTabletActor::HandleSetNodeAttr(
const TEvService::TEvSetNodeAttrRequest::TPtr& ev,
const TActorContext& ctx)
{
auto* msg = ev->Get();

const auto flags = msg->Record.GetFlags();
if (HasFlag(flags, NProto::TSetNodeAttrRequest::F_SET_ATTR_SIZE)) {
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvService::TEvSetNodeAttrResponse>(
std::move(error)));

return;
}
}

auto validator = [&] (const NProto::TSetNodeAttrRequest& request) {
return ValidateRequest(request, GetBlockSize());
};

if (!AcceptRequest<TEvService::TSetNodeAttrMethod>(ev, ctx, validator)) {
return;
}
auto* msg = ev->Get();
auto requestInfo = CreateRequestInfo(
ev->Sender,
ev->Cookie,
Expand Down
10 changes: 10 additions & 0 deletions cloud/filestore/libs/storage/tablet/tablet_actor_truncate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ void TIndexTabletActor::HandleTruncate(
const TEvIndexTabletPrivate::TEvTruncateRequest::TPtr& ev,
const TActorContext& ctx)
{
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvIndexTabletPrivate::TEvTruncateResponse>(
std::move(error)));

return;
}

auto* msg = ev->Get();

LOG_DEBUG(ctx, TFileStoreComponents::TABLET,
Expand Down
10 changes: 10 additions & 0 deletions cloud/filestore/libs/storage/tablet/tablet_actor_unlinknode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ void TIndexTabletActor::HandleUnlinkNode(
const TEvService::TEvUnlinkNodeRequest::TPtr& ev,
const TActorContext& ctx)
{
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvService::TEvUnlinkNodeResponse>(
std::move(error)));

return;
}

auto* session = AcceptRequest<TEvService::TUnlinkNodeMethod>(ev, ctx, ValidateRequest);
if (!session) {
return;
Expand Down
10 changes: 10 additions & 0 deletions cloud/filestore/libs/storage/tablet/tablet_actor_zerorange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ void TIndexTabletActor::HandleZeroRange(
const TEvIndexTabletPrivate::TEvZeroRangeRequest::TPtr& ev,
const TActorContext& ctx)
{
if (auto error = IsDataOperationAllowed(); HasError(error)) {
NCloud::Reply(
ctx,
*ev,
std::make_unique<TEvIndexTabletPrivate::TEvZeroRangeResponse>(
std::move(error)));

return;
}

auto* msg = ev->Get();

LOG_DEBUG(ctx, TFileStoreComponents::TABLET,
Expand Down
184 changes: 184 additions & 0 deletions cloud/filestore/libs/storage/tablet/tablet_ut_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3421,6 +3421,184 @@ Y_UNIT_TEST_SUITE(TIndexTabletTest_Data)
tablet.DestroyHandle(handle);
}

TABLET_TEST(ShouldNotAllowTruncateDuringCompactionMapLoading)
{
const auto block = tabletConfig.BlockSize;

NProto::TStorageConfig storageConfig;
storageConfig.SetCompactionThreshold(999'999);
storageConfig.SetCleanupThreshold(999'999);
storageConfig.SetLoadedCompactionRangesPerTx(2);
storageConfig.SetWriteBlobThreshold(block);

TTestEnv env({}, std::move(storageConfig));

env.CreateSubDomain("nfs");

bool intercepted = false;
TAutoPtr<IEventHandle> loadChunk;
env.GetRuntime().SetEventFilter([&] (auto& runtime, auto& event) {
Y_UNUSED(runtime);

switch (event->GetTypeRewrite()) {
case TEvIndexTabletPrivate::EvLoadCompactionMapChunkRequest: {
if (!intercepted) {
intercepted = true;
loadChunk = event.Release();
return true;
}
}
}

return false;
});

ui32 nodeIdx = env.CreateNode("nfs");
ui64 tabletId = env.BootIndexTablet(nodeIdx);

TIndexTabletClient tablet(
env.GetRuntime(),
nodeIdx,
tabletId,
tabletConfig);
tablet.InitSession("client", "session");

auto id = CreateNode(tablet, TCreateNodeArgs::File(RootNodeId, "test"));

// testing file size change - may trigger compaction map update via a
// truncate call
TSetNodeAttrArgs args(id);
args.SetFlag(NProto::TSetNodeAttrRequest::F_SET_ATTR_SIZE);
args.SetSize(4 * block);
tablet.SendSetNodeAttrRequest(args);
{
auto response = tablet.RecvSetNodeAttrResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

// testing some other requests that can potentially trigger compaction
// map update
tablet.SendAllocateDataRequest(0, 0, 0, 0);
{
auto response = tablet.RecvAllocateDataResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

tablet.SendDestroyCheckpointRequest("c");
{
auto response = tablet.RecvDestroyCheckpointResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

tablet.SendDestroyHandleRequest(0);
{
auto response = tablet.RecvDestroyHandleResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

tablet.SendDestroySessionRequest(0);
{
auto response = tablet.RecvDestroySessionResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

tablet.SendTruncateRequest(0, 0);
{
auto response = tablet.RecvTruncateResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

tablet.SendUnlinkNodeRequest(0, "", false);
{
auto response = tablet.RecvUnlinkNodeResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

tablet.SendZeroRangeRequest(0, 0, 0);
{
auto response = tablet.RecvZeroRangeResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

// checking that our state wasn't changed
{
auto response = tablet.GetStorageStats();
const auto& stats = response->Record.GetStats();
UNIT_ASSERT_VALUES_EQUAL(stats.GetMixedBlocksCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetMixedBlobsCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetDeletionMarkersCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetUsedBlocksCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetUsedCompactionRanges(), 0);
}

UNIT_ASSERT(loadChunk);

env.GetRuntime().Send(loadChunk.Release(), nodeIdx);

// compaction map should be loaded now - SetNodeAttr should succeed
tablet.SendSetNodeAttrRequest(args);
{
auto response = tablet.RecvSetNodeAttrResponse();
UNIT_ASSERT_VALUES_EQUAL(S_OK, response->GetStatus());
}

// we have some used blocks now
{
auto response = tablet.GetStorageStats();
const auto& stats = response->Record.GetStats();
UNIT_ASSERT_VALUES_EQUAL(stats.GetMixedBlocksCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetMixedBlobsCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetDeletionMarkersCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetUsedBlocksCount(), 4);
UNIT_ASSERT_VALUES_EQUAL(stats.GetUsedCompactionRanges(), 0);
}

intercepted = false;

tablet.RebootTablet();
tablet.RecoverSession();

// truncate to 0 size should not succeed before compaction map gets
// loaded as well
args.SetSize(0);
tablet.SendSetNodeAttrRequest(args);
{
auto response = tablet.RecvSetNodeAttrResponse();
UNIT_ASSERT_VALUES_EQUAL(E_REJECTED, response->GetStatus());
}

// state not changed
{
auto response = tablet.GetStorageStats();
const auto& stats = response->Record.GetStats();
UNIT_ASSERT_VALUES_EQUAL(stats.GetMixedBlocksCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetMixedBlobsCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetDeletionMarkersCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetUsedBlocksCount(), 4);
UNIT_ASSERT_VALUES_EQUAL(stats.GetUsedCompactionRanges(), 0);
}

env.GetRuntime().Send(loadChunk.Release(), nodeIdx);
// compaction map loaded - truncate request allowed
tablet.SendSetNodeAttrRequest(args);
{
auto response = tablet.RecvSetNodeAttrResponse();
UNIT_ASSERT_VALUES_EQUAL(S_OK, response->GetStatus());
}

// we should see some deletion markers now
{
auto response = tablet.GetStorageStats();
const auto& stats = response->Record.GetStats();
UNIT_ASSERT_VALUES_EQUAL(stats.GetMixedBlocksCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetMixedBlobsCount(), 0);
UNIT_ASSERT_VALUES_EQUAL(stats.GetDeletionMarkersCount(), 4);
UNIT_ASSERT_VALUES_EQUAL(stats.GetUsedBlocksCount(), 0);
// we have some deletion markers in one of the ranges now
UNIT_ASSERT_VALUES_EQUAL(stats.GetUsedCompactionRanges(), 1);
}
}

TABLET_TEST(ShouldDeduplicateOutOfOrderCompactionMapChunkLoads)
{
const auto block = tabletConfig.BlockSize;
Expand Down Expand Up @@ -3607,6 +3785,9 @@ Y_UNIT_TEST_SUITE(TIndexTabletTest_Data)
static_cast<ui32>(stats.GetBlobIndexOpState()));
}

env.GetRuntime().Send(loadChunk.Release(), nodeIdx);
env.GetRuntime().DispatchEvents({}, TDuration::Seconds(1));

tablet.DestroyHandle(handle);
}

Expand Down Expand Up @@ -3700,6 +3881,9 @@ Y_UNIT_TEST_SUITE(TIndexTabletTest_Data)
static_cast<ui32>(stats.GetFlushState()));
}

env.GetRuntime().Send(loadChunk.Release(), nodeIdx);
env.GetRuntime().DispatchEvents({}, TDuration::Seconds(1));

tablet.DestroyHandle(handle);
}

Expand Down

0 comments on commit ad0d642

Please sign in to comment.