Created
August 27, 2018 10:08
-
-
Save jdtournier/fe18f29a9acb22114163b69700682a82 to your computer and use it in GitHub Desktop.
Sample code to sync via filesystem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <stdexcept> | |
#include <stdexcept> | |
#include <sstream> | |
#include <cstring> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <fcntl.h> | |
#define TRACE std::cerr << __FILE__ << ": line " << __LINE__ << "\n"; | |
constexpr const char* sync_file = ".mrview.sync"; | |
constexpr int num_el = 100; | |
#ifdef _WIN32 | |
#include <windows.h> | |
# define SEP "\\" | |
#else | |
# define SEP "/" | |
#endif | |
inline const char* sync_filename () | |
{ | |
static std::string name = std::string (getenv ("HOME")) + SEP + sync_file; | |
return name.c_str(); | |
} | |
inline void error (const std::string& mesg) | |
{ | |
throw std::runtime_error (mesg + ": " + strerror (errno)); | |
} | |
class SyncData { | |
public: | |
float data [num_el]; | |
}; | |
void init_sync_file () | |
{ | |
int fd = open (sync_filename(), O_CREAT | O_RDWR | O_EXCL | O_BINARY, 0600); | |
if (fd < 0 && errno == EEXIST) | |
fd = open (sync_filename(), O_RDWR | O_BINARY); | |
if (fd < 0) | |
error ("failed to init sync file"); | |
if (ftruncate (fd, sizeof(SyncData))) | |
error ("error truncating sync file"); | |
close (fd); | |
} | |
void write_sync_data (const SyncData& data) | |
{ | |
int fd = open (sync_filename(), O_RDWR | O_BINARY); | |
if (fd < 0) | |
error ("failed to open sync file for writing"); | |
int nbytes = write (fd, reinterpret_cast<const void*> (&data), sizeof(SyncData)); | |
close (fd); | |
if (nbytes != sizeof(SyncData)) | |
error ("error writing sync data"); | |
} | |
void atomic_write_sync_data (const SyncData& data) | |
{ | |
std::ostringstream tmp; | |
tmp << sync_filename() << getpid(); | |
int fd = open (tmp.str().c_str(), O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); | |
if (fd < 0) | |
error ("failed to open temp sync file for writing"); | |
int nbytes = write (fd, reinterpret_cast<const void*> (&data), sizeof(SyncData)); | |
close (fd); | |
if (nbytes != sizeof(SyncData)) | |
error ("error writing sync data"); | |
#ifdef _WIN32 | |
while (!MoveFileEx(tmp.str().c_str(), sync_filename(), MOVEFILE_REPLACE_EXISTING)) | |
usleep (10); | |
#else | |
if (rename (tmp.str().c_str(), sync_filename())) | |
error ("error atomically replacing sync file"); | |
#endif | |
} | |
void read_sync_data (SyncData& data) | |
{ | |
int fd; | |
while ( (fd = open (sync_filename(), O_RDONLY | O_BINARY)) < 0)// && errno == EPERM) | |
usleep (10); | |
if (fd < 0) | |
error ("failed to open sync file for reading"); | |
int nbytes = read (fd, reinterpret_cast<void*> (&data), sizeof(SyncData)); | |
if (close (fd)) | |
error ("error closing sync file"); | |
if (nbytes < 0) | |
error ("error reading sync data"); | |
if (nbytes != sizeof(SyncData)) | |
error ("not enough sync data read"); | |
} | |
void prepare_sync_data (SyncData& data) | |
{ | |
float sum = 0.0; | |
for (int n = 0; n < num_el-1; ++n) | |
sum += data.data[n] = float (std::rand()) / RAND_MAX; | |
data.data[num_el-1] = sum; | |
} | |
int verify_sync_data (const SyncData& data) | |
{ | |
float sum = 0.0; | |
for (int n = 0; n < num_el-1; ++n) | |
sum += data.data[n]; | |
return data.data[num_el-1] != sum; | |
} | |
int main (int argc, const char* const argv[]) | |
{ | |
std::srand (getpid()); | |
init_sync_file(); | |
size_t total = 0, failures = 0; | |
while (true) { | |
for (int n = 0; n < 1000; ++n) { | |
SyncData data; | |
prepare_sync_data (data); | |
atomic_write_sync_data (data); | |
//write_sync_data (data); | |
read_sync_data (data); | |
failures += verify_sync_data (data); | |
total++; | |
} | |
std::cerr << failures << " / " << total << "\n"; | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Compile with:
and run multiple instances concurrently.
The program prepares a vector of 100 floats, with the last value being the sum of the rest as a checksum. It atomically writes this to file, then reads from file and verifies the checksum, in a tight loop. Multiple instances writing & reading concurrently should still produce consistent vectors that pass verification, even if they weren't what each instance just wrote.