Skip to content

Instantly share code, notes, and snippets.

@tahajahangir
Created December 10, 2013 06:51
Show Gist options
  • Save tahajahangir/7886704 to your computer and use it in GitHub Desktop.
Save tahajahangir/7886704 to your computer and use it in GitHub Desktop.
A simple FreeBSD file syncer that can `fsync` a large file chunk-by-chunk.
/**
* Compile:
* $ g++ -Wall -o msync msync.cpp
* Usage:
* $ msync FILE [WAIT_FACTOR]
* WAIT_FACTOR is a float that changes wait time between syncing two
* chunks (each CHUNK is 10MB). Wait time is factor of sync time, so
* if WAIT_FACTOR is 2.0 (default), if syncing 10MB takes 1 seconds,
* the program waits 2 second after that step.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#define KB * 1024
#define MB * 1024 KB
#define GB * 1024 MB
#define CHUNK 10 MB
off_t fsize(const char *filename) {
struct stat st;
if (stat(filename, &st) == 0)
return st.st_size;
return -1;
}
int main(int argc, char *argv[])
{
if (argc <= 1) {
perror("Not enough arguments, pass at least one\n");
exit(EXIT_FAILURE);
}
char* file_path = argv[1];
float wait_factor = 2.0;
if (argc > 2) {
sscanf(argv[2], "%f", &wait_factor);
}
off_t file_size = fsize(file_path);
int fd;
char *map; /* mmapped array of int's */
fd = open(file_path, O_RDONLY);
if (fd == -1) {
perror("Error opening file for reading");
exit(EXIT_FAILURE);
}
map = (char*) mmap(0, file_size, PROT_READ, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
struct timespec begin, end_time;
off_t cursor = 0;
size_t len;
long waited_u;
while (cursor < file_size) {
len = cursor + CHUNK < file_size ? CHUNK : (file_size - cursor);
clock_gettime(CLOCK_MONOTONIC, &begin);
if (msync(&map[cursor], len, MS_SYNC) == -1) {
perror("Error msync");
}
clock_gettime(CLOCK_MONOTONIC, &end_time);
cursor += len;
waited_u = (end_time.tv_sec - begin.tv_sec) * 1000000 + (end_time.tv_nsec - begin.tv_nsec) / 1000;
// if (waited_u > 1000) {
// printf("waited %d microseconds, cursor: %lld \n", waited_u, cursor);
// }
usleep(waited_u * wait_factor);
}
if (munmap(map, file_size) == -1) {
perror("Error un-mmapping the file");
}
close(fd);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment