1

Trying to let multiple processes across different Linux nodes write to a shared CSV file on a Windows shared folder.

I tested if it works by launching 2 processes on separate nodes, each appending 10k lines to a file. Then I check if the line count is 20k. Unfortunately, the line count is almost always less than that. I'm using Linux 3.0.51 and Windows Server 2008 R2. However, locking across multiple processes within 1 node does work with flock(), but not fcntl().

Here are some other things I tried:

  1. Use NFS - does work! (sometimes line count is 19999)

  2. Use Linux kernel 4.10 and mount as SMB 3.02 - doesn't work

  3. Using Samba as the server - doesn't work, even with strict locking = yes as described here:

https://www.samba.org/samba/docs/man/Samba-HOWTO-Collection/locking.html

Has anyone got this to work or know it can't be done (and for what configuration)? Here's my test program:

#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/file.h>
#include <boost/interprocess/sync/file_lock.hpp>
// method 0: fcntl() - works for NFS and across multiple nodes, but not for CIFS/SMB
// method 1: flock() - works for SMB within 1 node, but not accross multiple nodes
// method 2: Boost   (internally uses fcntl)
#define METHOD 1
using namespace std;
class FileLock
{
public:
#if METHOD == 2
  FileLock(const char *path) : lock(path)
  {
  }
#else
  FileLock(int f)
  {
    file = f;
#if METHOD == 0
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
#endif
  }
#endif
  bool Lock()
  {
#if METHOD == 0
    lock.l_type = F_WRLCK;
    return fcntl(file, F_SETLKW, &lock) == 0;
#elif METHOD == 1
    return flock(file, LOCK_EX) == 0;
#elif METHOD == 2
    lock.lock();
    return true;
#endif
  }
  bool Unlock()
  {
#if METHOD == 0
    lock.l_type = F_UNLCK;
    return fcntl(file, F_SETLKW, &lock) == 0;
#elif METHOD == 1
    return flock(file, LOCK_UN) == 0;
#elif METHOD == 2
    lock.unlock();
    return true;
#endif
  }
  int file;
#if METHOD == 0
  struct flock lock;
#elif METHOD == 2
  boost::interprocess::file_lock lock;
#endif
};

int main(int argc, char **argv)
{
  int repeats = 100;
  double interval = 0.1;
  char message[256];
  sprintf(message, "testing 123\n");

  if (argc >= 2)
    repeats = atoi(argv[1]);
  if (argc >= 3)
    interval = atof(argv[2]);
  if (argc >= 4)
  {
    sprintf(message, "%s\n", argv[3]);
  }
  FILE *f = fopen("a.txt", "a");
  if (f == NULL)
  {
    cout << "can't open" << endl;
    return 1;
  }
#if METHOD == 2
  FileLock lock("a.txt");
#else
  FileLock lock(fileno(f));
#endif
  for (int i = 0; i < repeats; ++i)
  {
    if (!lock.Lock())
     cout << "error locking " << strerror(errno) <<  "\n";

    // file in append mode will automatically write to end, but does it work when there are multiple writers?
    fseek(f, 0, SEEK_END);
    fwrite(message, 1, strlen(message), f);

    if (!lock.Unlock())
      cout << "error unlocking\n";
    usleep(interval * 1000000);
  }
  fclose(f);
  return 0;
}
Yale Zhang
  • 1,447
  • 12
  • 30

0 Answers0