Merge pull request #4418 from sfc-gh-mpilman/features/async-rename

Add async rename
This commit is contained in:
Steve Atherton 2021-03-03 14:29:13 -08:00 committed by GitHub
commit 02e575e49b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 118 additions and 6 deletions

View File

@ -107,6 +107,33 @@ public:
return Void();
}
ACTOR static Future<Void> renameFile(std::string from, std::string to) {
state TaskPriority taskID = g_network->getCurrentTask();
state Promise<Void> p;
state eio_req* r = eio_rename(from.c_str(), to.c_str(), 0, eio_callback, &p);
try {
wait(p.getFuture());
} catch (...) {
g_network->setCurrentTask(taskID);
eio_cancel(r);
throw;
}
try {
state int result = r->result;
if(result == -1) {
TraceEvent(SevError, "FileRenameError").detail("Errno", r->errorno);
throw internal_error();
} else {
wait(delay(0, taskID));
return Void();
}
} catch (Error& e) {
state Error _e = e;
wait(delay(0, taskID));
throw _e;
}
}
ACTOR static Future<std::time_t> lastWriteTime( std::string filename ) {
EIO_STRUCT_STAT statdata = wait(stat_impl(filename));
return statdata.st_mtime;

View File

@ -128,6 +128,12 @@ public:
return result.getFuture();
}
static Future<Void> renameFile(std::string const& from, std::string const& to) {
::renameFile(from, to);
return Void();
}
virtual Future<Void> write( void const* data, int length, int64_t offset ) {
/*
FIXME

View File

@ -132,3 +132,55 @@ TEST_CASE("/fileio/incrementalDelete" ) {
wait(IAsyncFileSystem::filesystem()->incrementalDeleteFile(filename, true));
return Void();
}
TEST_CASE("/fileio/rename") {
// create a file
state int64_t fileSize = 100e6;
state std::string filename = "/tmp/__JUNK__." + deterministicRandom()->randomUniqueID().toString();
state std::string renamedFile = "/tmp/__RENAMED_JUNK__." + deterministicRandom()->randomUniqueID().toString();
state std::unique_ptr<char[]> data(new char[4096]);
state std::unique_ptr<char[]> readData(new char[4096]);
state Reference<IAsyncFile> f = wait(IAsyncFileSystem::filesystem()->open(
filename, IAsyncFile::OPEN_ATOMIC_WRITE_AND_CREATE | IAsyncFile::OPEN_CREATE | IAsyncFile::OPEN_READWRITE,
0644));
;
wait(f->sync());
wait(f->truncate(fileSize));
memset(data.get(), 0, 4096);
// write a random string at the beginning of the file which we can verify after rename
for (int i = 0; i < 16; ++i) {
data[i] = deterministicRandom()->randomAlphaNumeric();
}
// write first and block
wait(f->write(data.get(), 4096, 0));
wait(f->write(data.get(), 4096, fileSize - 4096));
wait(f->sync());
// close file
f.clear();
wait(IAsyncFileSystem::filesystem()->renameFile(filename, renamedFile));
Reference<IAsyncFile> _f = wait(IAsyncFileSystem::filesystem()->open(renamedFile, IAsyncFile::OPEN_READONLY, 0));
f = _f;
// verify rename happened
bool renamedExists = false;
auto bName = basename(renamedFile);
auto files = platform::listFiles("/tmp/");
for (const auto& file : files) {
if (file == bName) {
renamedExists = true;
}
ASSERT(file != filename);
}
ASSERT(renamedExists);
// verify magic string at beginning of file
int length = wait(f->read(readData.get(), 4096, 0));
ASSERT(length == 4096);
ASSERT(memcmp(readData.get(), data.get(), 4096) == 0);
// close the file
f.clear();
// clean up
wait(IAsyncFileSystem::filesystem()->deleteFile(renamedFile, true));
return Void();
}

View File

@ -20,6 +20,7 @@
#ifndef FLOW_IASYNCFILE_H
#define FLOW_IASYNCFILE_H
#include <string>
#pragma once
#include <ctime>
@ -98,6 +99,9 @@ public:
// Deletes the given file. If mustBeDurable, returns only when the file is guaranteed to be deleted even after a power failure.
virtual Future< Void > deleteFile( std::string filename, bool mustBeDurable ) = 0;
// renames the file, doesn't sync the directory
virtual Future<Void> renameFile(std::string const& from, std::string const& to) = 0;
// Unlinks a file and then deletes it slowly by truncating the file repeatedly.
// If mustBeDurable, returns only when the file is guaranteed to be deleted even after a power failure.
virtual Future<Void> incrementalDeleteFile( std::string filename, bool mustBeDurable );

View File

@ -115,6 +115,10 @@ Net2FileSystem::Net2FileSystem(double ioTimeout, std::string fileSystemPath)
#endif
}
Future<Void> Net2FileSystem::renameFile(const std::string &from, const std::string &to) {
return Net2AsyncFile::renameFile(from, to);
}
void Net2FileSystem::stop() {
Net2AsyncFile::stop();
}

View File

@ -20,6 +20,7 @@
#ifndef FLOW_NET2FILESYSTEM_H
#define FLOW_NET2FILESYSTEM_H
#include <string>
#pragma once
#include "fdbrpc/IAsyncFile.h"
@ -27,13 +28,15 @@
class Net2FileSystem : public IAsyncFileSystem {
public:
// Opens a file for asynchronous I/O
virtual Future< Reference<class IAsyncFile> > open( std::string filename, int64_t flags, int64_t mode );
Future< Reference<class IAsyncFile> > open( std::string filename, int64_t flags, int64_t mode ) override;
// Deletes the given file. If mustBeDurable, returns only when the file is guaranteed to be deleted even after a power failure.
virtual Future< Void > deleteFile( std::string filename, bool mustBeDurable );
Future< Void > deleteFile( std::string filename, bool mustBeDurable ) override;
Future<Void> renameFile(std::string const& from, std::string const& to) override;
// Returns the time of the last modification of the file.
virtual Future< std::time_t > lastWriteTime( std::string filename );
Future< std::time_t > lastWriteTime( std::string filename ) override;
//void init();
static void stop();

View File

@ -19,8 +19,10 @@
*/
#include <cinttypes>
#include <string>
#include "fdbrpc/simulator.h"
#include "flow/flow.h"
#include "flow/IThreadPool.h"
#include "flow/Util.h"
#include "fdbrpc/IAsyncFile.h"
@ -1847,6 +1849,17 @@ Future< Void > Sim2FileSystem::deleteFile( std::string filename, bool mustBeDura
return Sim2::deleteFileImpl(&g_sim2, filename, mustBeDurable);
}
ACTOR Future<Void> renameFileImpl(std::string from, std::string to) {
wait(delay(0.5*deterministicRandom()->random01()));
::renameFile(from, to);
wait(delay(0.5*deterministicRandom()->random01()));
return Void();
}
Future<Void> Sim2FileSystem::renameFile(std::string const& from, std::string const& to) {
return renameFileImpl(from, to);
}
Future< std::time_t > Sim2FileSystem::lastWriteTime( std::string filename ) {
// TODO: update this map upon file writes.
static std::map<std::string, double> fileWrites;

View File

@ -20,6 +20,7 @@
#ifndef FLOW_SIMULATOR_H
#define FLOW_SIMULATOR_H
#include <string>
#pragma once
#include "flow/flow.h"
@ -361,12 +362,14 @@ extern Future<Void> waitUntilDiskReady(Reference<DiskParameters> parameters, int
class Sim2FileSystem : public IAsyncFileSystem {
public:
// Opens a file for asynchronous I/O
virtual Future< Reference<class IAsyncFile> > open( std::string filename, int64_t flags, int64_t mode );
Future<Reference<class IAsyncFile>> open( std::string filename, int64_t flags, int64_t mode ) override;
// Deletes the given file. If mustBeDurable, returns only when the file is guaranteed to be deleted even after a power failure.
virtual Future< Void > deleteFile( std::string filename, bool mustBeDurable );
Future<Void> deleteFile(std::string filename, bool mustBeDurable) override;
virtual Future< std::time_t > lastWriteTime( std::string filename );
Future<Void> renameFile(std::string const& from, std::string const& to) override;
Future< std::time_t > lastWriteTime( std::string filename ) override;
Sim2FileSystem() {}