diff --git a/cloud/filestore/libs/storage/api/service.h b/cloud/filestore/libs/storage/api/service.h index 6b87d6df25e..c25e580a8dc 100644 --- a/cloud/filestore/libs/storage/api/service.h +++ b/cloud/filestore/libs/storage/api/service.h @@ -35,9 +35,6 @@ namespace NCloud::NFileStore::NStorage { xxx(RenameNode, __VA_ARGS__) \ xxx(ReadLink, __VA_ARGS__) \ \ - xxx(AcquireLock, __VA_ARGS__) \ - xxx(ReleaseLock, __VA_ARGS__) \ - xxx(TestLock, __VA_ARGS__) \ // FILESTORE_SERVICE_REQUESTS_FWD #define FILESTORE_SERVICE_REQUESTS_FWD_TO_FOLLOWER_BY_NODE_ID(xxx, ...) \ @@ -52,6 +49,10 @@ namespace NCloud::NFileStore::NStorage { #define FILESTORE_SERVICE_REQUESTS_FWD_TO_FOLLOWER_BY_HANDLE(xxx, ...) \ xxx(DestroyHandle, __VA_ARGS__) \ xxx(AllocateData, __VA_ARGS__) \ + \ + xxx(AcquireLock, __VA_ARGS__) \ + xxx(ReleaseLock, __VA_ARGS__) \ + xxx(TestLock, __VA_ARGS__) \ // FILESTORE_SERVICE_REQUESTS_FWD_TO_FOLLOWER_BY_NODE_ID #define FILESTORE_SERVICE_REQUESTS_HANDLE(xxx, ...) \ diff --git a/cloud/filestore/libs/storage/service/service_ut.cpp b/cloud/filestore/libs/storage/service/service_ut.cpp index 44573efa620..6152815a4ef 100644 --- a/cloud/filestore/libs/storage/service/service_ut.cpp +++ b/cloud/filestore/libs/storage/service/service_ut.cpp @@ -3805,6 +3805,93 @@ Y_UNIT_TEST_SUITE(TStorageServiceTest) getNodeAttrResponse->GetErrorReason().c_str()); } + Y_UNIT_TEST(ShouldPerformLocksForExternalNodes) + { + NProto::TStorageConfig config; + config.SetMultiTabletForwardingEnabled(true); + TTestEnv env({}, config); + env.CreateSubDomain("nfs"); + + ui32 nodeIdx = env.CreateNode("nfs"); + + const TString fsId = "test"; + const auto shard1Id = fsId + "-f1"; + const auto shard2Id = fsId + "-f2"; + + TServiceClient service(env.GetRuntime(), nodeIdx); + service.CreateFileStore(fsId, 1'000); + service.CreateFileStore(shard1Id, 1'000); + service.CreateFileStore(shard2Id, 1'000); + + ConfigureFollowers(service, fsId, shard1Id, shard2Id); + + auto headers = service.InitSession(fsId, "client"); + + ui64 nodeId = service + .CreateNode(headers, TCreateNodeArgs::File(RootNodeId, "file")) + ->Record.GetNode() + .GetId(); + ui64 handle = service + .CreateHandle(headers, fsId, nodeId, "", TCreateHandleArgs::RDWR) + ->Record.GetHandle(); + + service.AcquireLock(headers, fsId, handle, 1, 0, 4_KB); + + auto response = + service.AssertAcquireLockFailed(headers, fsId, handle, 2, 0, 4_KB); + UNIT_ASSERT_VALUES_EQUAL(response->GetError().GetCode(), E_FS_WOULDBLOCK); + + service.ReleaseLock(headers, fsId, handle, 2, 0, 4_KB); + service.AcquireLock(headers, fsId, handle, 1, 0, 0); + + response = + service.AssertAcquireLockFailed(headers, fsId, handle, 2, 0, 4_KB); + UNIT_ASSERT_VALUES_EQUAL(response->GetError().GetCode(), E_FS_WOULDBLOCK); + + service.ReleaseLock(headers, fsId, handle, 1, 0, 0); + + // ShouldTrackSharedLocks + + service.AcquireLock( + headers, + fsId, + handle, + 1, + 0, + 4_KB, + DefaultPid, + NProto::E_SHARED); + service.AcquireLock( + headers, + fsId, + handle, + 2, + 0, + 4_KB, + DefaultPid, + NProto::E_SHARED); + + response = + service.AssertAcquireLockFailed(headers, fsId, handle, 1, 0, 0); + UNIT_ASSERT_VALUES_EQUAL( + response->GetError().GetCode(), + E_FS_WOULDBLOCK); + + response = service.AssertAcquireLockFailed(headers, fsId, handle, 1, 0, 0); + UNIT_ASSERT_VALUES_EQUAL(response->GetError().GetCode(), E_FS_WOULDBLOCK); + + service.AcquireLock(headers, fsId, handle, 3, 0, 4_KB, DefaultPid, NProto::E_SHARED); + + service.DestroyHandle(headers, fsId, nodeId, handle); + + handle = service + .CreateHandle(headers, fsId, nodeId, "", TCreateHandleArgs::WRNLY) + ->Record.GetHandle(); + + service.AssertTestLockFailed(headers, fsId, handle, 1, 0, 4_KB, DefaultPid, NProto::E_SHARED); + service.AssertAcquireLockFailed(headers, fsId, handle, 1, 0, 4_KB, DefaultPid, NProto::E_SHARED); + } + Y_UNIT_TEST(ShouldLinkExternalNodes) { NProto::TStorageConfig config; diff --git a/cloud/filestore/libs/storage/testlib/service_client.h b/cloud/filestore/libs/storage/testlib/service_client.h index d3e3553f747..9a6859c1d9a 100644 --- a/cloud/filestore/libs/storage/testlib/service_client.h +++ b/cloud/filestore/libs/storage/testlib/service_client.h @@ -22,6 +22,8 @@ class TServiceClient ui32 NodeIdx; NActors::TActorId Sender; + static constexpr i32 DefaultPid = 123; + public: TServiceClient(NKikimr::TTestActorRuntime& runtime, ui32 nodeIdx) : Runtime(runtime) @@ -476,6 +478,79 @@ class TServiceClient return request; } + std::unique_ptr CreateAcquireLockRequest( + const THeaders& headers, + const TString& fileSystemId, + ui64 handle, + ui64 owner, + ui64 offset, + ui64 len, + i32 pid = DefaultPid, + NProto::ELockType type = NProto::E_EXCLUSIVE, + NProto::ELockOrigin origin = NProto::E_FCNTL) + { + auto request = std::make_unique(); + headers.Fill(request->Record); + auto& record = request->Record; + record.SetFileSystemId(fileSystemId); + record.SetHandle(handle); + record.SetOwner(owner); + record.SetOffset(offset); + record.SetLength(len); + record.SetPid(pid); + record.SetLockType(type); + record.SetLockOrigin(origin); + return request; + } + + std::unique_ptr CreateReleaseLockRequest( + const THeaders& headers, + const TString& fileSystemId, + ui64 handle, + ui64 owner, + ui64 offset, + ui64 len, + i32 pid = DefaultPid, + NProto::ELockOrigin origin = NProto::E_FCNTL) + { + auto request = std::make_unique(); + headers.Fill(request->Record); + auto& record = request->Record; + record.SetFileSystemId(fileSystemId); + record.SetHandle(handle); + record.SetOwner(owner); + record.SetOffset(offset); + record.SetLength(len); + record.SetPid(pid); + record.SetLockOrigin(origin); + return request; + } + + std::unique_ptr CreateTestLockRequest( + const THeaders& headers, + const TString& fileSystemId, + ui64 handle, + ui64 owner, + ui64 offset, + ui64 len, + i32 pid = DefaultPid, + NProto::ELockType type = NProto::E_EXCLUSIVE, + NProto::ELockOrigin origin = NProto::E_FCNTL) + { + auto request = std::make_unique(); + headers.Fill(request->Record); + auto& record = request->Record; + record.SetFileSystemId(fileSystemId); + record.SetHandle(handle); + record.SetOwner(owner); + record.SetOffset(offset); + record.SetLength(len); + record.SetPid(pid); + record.SetLockType(type); + record.SetLockOrigin(origin); + return request; + } + #define FILESTORE_DECLARE_METHOD(name, ns) \ template \ void Send##name##Request(Args&&... args) \