/*
 *	test_fsync.c
 *		tests if fsync can be done from another process than the original write
 */

#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

void die(char *str);
void print_elapse(struct timeval start_t, struct timeval elapse_t);

int main(int argc, char *argv[])
{
	struct timeval start_t;
	struct timeval elapse_t;
	int tmpfile, i;
	char *strout = (char *) malloc(65536);  

	for (i=0; i<65536; i++)
		strout[i] = 'a';

	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	write(tmpfile, strout, 65536);
	fsync(tmpfile);
	close(tmpfile);		

	/* write only */	
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	gettimeofday(&start_t, NULL);
	write(tmpfile, strout, 8192);
	write(tmpfile, strout, 8192);
	gettimeofday(&elapse_t, NULL);
	close(tmpfile);		
	printf("write                      ");
	print_elapse(start_t, elapse_t);
	printf("\n");

	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	fsync(tmpfile);
	close(tmpfile);		

	/* write & fsync */
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	gettimeofday(&start_t, NULL);
	write(tmpfile, strout, 8192);
	write(tmpfile, strout, 8192);
	fsync(tmpfile);
	gettimeofday(&elapse_t, NULL);
	close(tmpfile);		
	printf("write & fsync              ");
	print_elapse(start_t, elapse_t);
	printf("\n");

	/* write & fdatasync */
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	gettimeofday(&start_t, NULL);
	write(tmpfile, strout, 8192);
	write(tmpfile, strout, 8192);
	fdatasync(tmpfile);
	gettimeofday(&elapse_t, NULL);
	close(tmpfile);		
	printf("write & fdatasync          ");
	print_elapse(start_t, elapse_t);
	printf("\n");

	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	fsync(tmpfile);
	close(tmpfile);		

	/* write, close & fsync */
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open 1 /var/tmp/test_fsync.out");
	gettimeofday(&start_t, NULL);
	write(tmpfile, strout, 8192);
	write(tmpfile, strout, 8192);
	close(tmpfile);
	/* reopen file */
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open 2 /var/tmp/test_fsync.out");
	fsync(tmpfile);
	close(tmpfile);		
	gettimeofday(&elapse_t, NULL);
	printf("write, close & fsync       ");
	print_elapse(start_t, elapse_t);
	printf("\n");

	/* write, close & fdatasync */
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open 1 /var/tmp/test_fsync.out");
	gettimeofday(&start_t, NULL);
	write(tmpfile, strout, 8192);
	write(tmpfile, strout, 8192);
	close(tmpfile);
	/* reopen file */
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open 2 /var/tmp/test_fsync.out");
	fdatasync(tmpfile);
	gettimeofday(&elapse_t, NULL);
	close(tmpfile);		
	printf("write, close & fdatasync   ");
	print_elapse(start_t, elapse_t);
	printf("\n");

	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	fsync(tmpfile);
	close(tmpfile);		

	/* open_dsync, write */
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR | O_DSYNC)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	gettimeofday(&start_t, NULL);
	write(tmpfile, strout, 8192);
	write(tmpfile, strout, 8192);
	gettimeofday(&elapse_t, NULL);
	close(tmpfile);
	printf("open o_dsync, write        ");
	print_elapse(start_t, elapse_t);
	printf("\n");

	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	fsync(tmpfile);
	close(tmpfile);		

	/* open_dsync, write */
	if ((tmpfile = open("/var/tmp/test_fsync.out", O_RDWR | O_DSYNC)) == -1)
		die("can't open /var/tmp/test_fsync.out");
	gettimeofday(&start_t, NULL);
	write(tmpfile, strout, 16384);
	gettimeofday(&elapse_t, NULL);
	close(tmpfile);
	printf("open o_dsync, one write    ");
	print_elapse(start_t, elapse_t);
	printf("\n");

	unlink("/var/tmp/test_fsync.out");

	return 0;
}

void print_elapse(struct timeval start_t, struct timeval elapse_t)
{
	if (elapse_t.tv_usec < start_t.tv_usec)
	{
		elapse_t.tv_sec--;
		elapse_t.tv_usec += 1000000;
	}

	printf("%ld.%06ld", (long) (elapse_t.tv_sec - start_t.tv_sec),
					 (long) (elapse_t.tv_usec - start_t.tv_usec));
}

void die(char *str)
{
	fprintf(stderr, "%s", str);
	exit(1);
}
