Skip to content

Instantly share code, notes, and snippets.

@jdtournier
Created August 27, 2018 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdtournier/fe18f29a9acb22114163b69700682a82 to your computer and use it in GitHub Desktop.
Save jdtournier/fe18f29a9acb22114163b69700682a82 to your computer and use it in GitHub Desktop.
Sample code to sync via filesystem
#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;
}
@jdtournier
Copy link
Author

Compile with:

g++ -std=c++11 test_sync.cpp -o test_sync

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment