diff options
| author | Martin Ridgers <[email protected]> | 2021-10-20 15:59:21 +0200 |
|---|---|---|
| committer | Martin Ridgers <[email protected]> | 2021-10-25 08:46:34 +0200 |
| commit | c825937c18dddfd75b58c5c9a86eb309e913c696 (patch) | |
| tree | f502ccfe5f3d3f3468ad397ade719f020e36cb51 | |
| parent | Added .gdb_history to .gitignore (diff) | |
| download | zen-c825937c18dddfd75b58c5c9a86eb309e913c696.tar.xz zen-c825937c18dddfd75b58c5c9a86eb309e913c696.zip | |
Implemented filecas.cpp for POSIX platforms
| -rw-r--r-- | zenstore/filecas.cpp | 94 |
1 files changed, 92 insertions, 2 deletions
diff --git a/zenstore/filecas.cpp b/zenstore/filecas.cpp index 3eccf53ff..6d385a208 100644 --- a/zenstore/filecas.cpp +++ b/zenstore/filecas.cpp @@ -86,6 +86,9 @@ FileCasStrategy::InsertChunk(IoBuffer Chunk, const IoHash& ChunkHash) { ShardingHelper Name(m_Config.RootDirectory.c_str(), ChunkHash); + RwLock::ExclusiveLockScope _(LockForHash(ChunkHash)); + +#if ZEN_PLATFORM_WINDOWS const HANDLE ChunkFileHandle = FileRef.FileHandle; auto DeletePayloadFileOnClose = [&] { @@ -106,8 +109,6 @@ FileCasStrategy::InsertChunk(IoBuffer Chunk, const IoHash& ChunkHash) // // Future improvement: maintain Bloom filter to avoid expensive file system probes? - RwLock::ExclusiveLockScope _(LockForHash(ChunkHash)); - { CAtlFile PayloadFile; @@ -226,6 +227,49 @@ FileCasStrategy::InsertChunk(IoBuffer Chunk, const IoHash& ChunkHash) ChunkHash); DeletePayloadFileOnClose(); +#elif ZEN_PLATFORM_LINUX + std::filesystem::path SourcePath = PathFromHandle(FileRef.FileHandle); + std::filesystem::path DestPath = Name.ShardedPath.c_str(); + int Ret = link(SourcePath.c_str(), DestPath.c_str()); + if (Ret < 0 && zen::GetLastError() == ENOENT) + { + // Destination directory doesn't exist. Create it any try again. + CreateDirectories(DestPath.parent_path().c_str()); + Ret = link(SourcePath.c_str(), DestPath.c_str()); + } + int LinkError = zen::GetLastError(); + + // Unlink the file. If the path to unlink didn't exist someone else + // beat us to it and that is hunky-dory. + if (unlink(SourcePath.c_str()) < 0) + { + int UnlinkError = zen::GetLastError(); + if (UnlinkError != ENOENT) + { + ZEN_WARN("unlink of CAS payload file failed ('{}')", GetSystemErrorAsString(UnlinkError)); + } + } + + // It is possible that someone beat us to it in linking the file. In that + // case a "file exists" error is okay. All others are not. + if (Ret < 0) + { + if (LinkError == EEXIST) + { + return CasStore::InsertResult{.New = false}; + } + + ZEN_WARN("link of CAS payload file failed ('{}'), falling back to regular write for insert of {}", + GetSystemErrorAsString(LinkError), + ChunkHash); + } + else + { + return CasStore::InsertResult{.New = true}; + } +#else +# error check link/unlink for this platform +#endif // ZEN_PLATFORM_* } return InsertChunk(Chunk.Data(), Chunk.Size(), ChunkHash); @@ -240,6 +284,7 @@ FileCasStrategy::InsertChunk(const void* const ChunkData, const size_t ChunkSize // // Future improvement: maintain Bloom filter to avoid expensive file system probes? +#if ZEN_PLATFORM_WINDOWS CAtlFile PayloadFile; HRESULT hRes = PayloadFile.Create(Name.ShardedPath.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING); @@ -252,9 +297,18 @@ FileCasStrategy::InsertChunk(const void* const ChunkData, const size_t ChunkSize } PayloadFile.Close(); +#elif ZEN_PLATFORM_LINUX + if (access(Name.ShardedPath.c_str(), F_OK) == 0) + { + return CasStore::InsertResult{.New = false}; + } +#else +# error Check access() for this platform +#endif RwLock::ExclusiveLockScope _(LockForHash(ChunkHash)); +#if ZEN_PLATFORM_WINDOWS // For now, use double-checked locking to see if someone else was first hRes = PayloadFile.Create(Name.ShardedPath.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING); @@ -288,6 +342,42 @@ FileCasStrategy::InsertChunk(const void* const ChunkData, const size_t ChunkSize { ThrowSystemException(hRes, "Failed to open shard file '{}'"_format(WideToUtf8(Name.ShardedPath))); } +#else + // Attempt to exclusively create the file. + auto InternalCreateFile = [&] { return open(Name.ShardedPath.c_str(), O_WRONLY|O_CREAT|O_EXCL, 0666); }; + int Fd = InternalCreateFile(); + if (Fd < 0) + { + switch (zen::GetLastError()) + { + case EEXIST: + // Another thread has beat us to it so we're golden. + return {.New = false}; + + case ENOENT: + if (zen::CreateDirectories(std::string_view(Name.ShardedPath.c_str(), Name.Shard2len))) + { + Fd = InternalCreateFile(); + if (Fd >= 0) + { + break; + } + } + ThrowLastError("Failed creating shard directory '{}'"_format(Name.ShardedPath)); + + default: + ThrowLastError("Unexpected error occurred opening shard file '{}'"_format(Name.ShardedPath)); + } + } + + struct FdWrapper + { + ~FdWrapper() { Close(); } + void Write(const void* Cursor, size_t Size) { (void)!write(Fd, Cursor, Size); } + void Close() { if (Fd >= 0) { close(Fd); Fd = -1; } } + int Fd; + } PayloadFile = { Fd }; +#endif // ZEN_PLATFORM_WINDOWS size_t ChunkRemain = ChunkSize; auto ChunkCursor = reinterpret_cast<const uint8_t*>(ChunkData); |