2013-04-17 00:00:59 -04:00
|
|
|
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
|
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
|
|
|
|
#ident "$Id$"
|
|
|
|
#ident "Copyright (c) 2007-2012 Tokutek Inc. All rights reserved."
|
2013-04-16 23:59:09 -04:00
|
|
|
|
2013-04-16 23:57:41 -04:00
|
|
|
#include <toku_portability.h>
|
2013-04-16 23:57:38 -04:00
|
|
|
#include <unistd.h>
|
2013-04-16 23:58:06 -04:00
|
|
|
#include <errno.h>
|
2013-04-16 23:58:56 -04:00
|
|
|
#include <toku_assert.h>
|
2013-04-16 23:58:06 -04:00
|
|
|
#include <stdio.h>
|
2013-04-16 23:59:02 -04:00
|
|
|
#include <string.h>
|
2013-04-16 23:59:02 -04:00
|
|
|
#include <dirent.h>
|
2013-04-16 23:59:13 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2013-04-17 00:01:08 -04:00
|
|
|
|
2013-04-16 23:59:16 -04:00
|
|
|
#include "memory.h"
|
2013-04-17 00:01:08 -04:00
|
|
|
#include "toku_time.h"
|
2013-04-16 23:59:02 -04:00
|
|
|
|
2013-04-16 23:59:02 -04:00
|
|
|
static int toku_assert_on_write_enospc = 0;
|
2013-04-16 23:59:02 -04:00
|
|
|
static const int toku_write_enospc_sleep = 1;
|
2013-04-16 23:59:02 -04:00
|
|
|
static uint64_t toku_write_enospc_last_report; // timestamp of most recent report to error log
|
|
|
|
static time_t toku_write_enospc_last_time; // timestamp of most recent ENOSPC
|
|
|
|
static uint32_t toku_write_enospc_current; // number of threads currently blocked on ENOSPC
|
|
|
|
static uint64_t toku_write_enospc_total; // total number of times ENOSPC was returned from an attempt to write
|
2013-04-16 23:59:02 -04:00
|
|
|
|
2013-04-16 23:59:02 -04:00
|
|
|
void toku_set_assert_on_write_enospc(int do_assert) {
|
|
|
|
toku_assert_on_write_enospc = do_assert;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_fs_get_write_info(time_t *enospc_last_time, uint64_t *enospc_current, uint64_t *enospc_total) {
|
2013-04-16 23:59:02 -04:00
|
|
|
*enospc_last_time = toku_write_enospc_last_time;
|
|
|
|
*enospc_current = toku_write_enospc_current;
|
|
|
|
*enospc_total = toku_write_enospc_total;
|
|
|
|
}
|
2013-04-16 23:58:06 -04:00
|
|
|
|
|
|
|
//Print any necessary errors
|
|
|
|
//Return whether we should try the write again.
|
2013-04-16 23:58:58 -04:00
|
|
|
static void
|
2013-04-16 23:58:06 -04:00
|
|
|
try_again_after_handling_write_error(int fd, size_t len, ssize_t r_write) {
|
|
|
|
int try_again = 0;
|
|
|
|
|
2013-04-16 23:58:58 -04:00
|
|
|
assert(r_write < 0);
|
2013-04-17 00:00:58 -04:00
|
|
|
int errno_write = get_error_errno();
|
2013-04-16 23:58:58 -04:00
|
|
|
switch (errno_write) {
|
2013-04-16 23:59:02 -04:00
|
|
|
case EINTR: { //The call was interrupted by a signal before any data was written; see signal(7).
|
|
|
|
char err_msg[sizeof("Write of [] bytes to fd=[] interrupted. Retrying.") + 20+10]; //64 bit is 20 chars, 32 bit is 10 chars
|
2013-04-17 00:00:58 -04:00
|
|
|
snprintf(err_msg, sizeof(err_msg), "Write of [%" PRIu64 "] bytes to fd=[%d] interrupted. Retrying.", (uint64_t)len, fd);
|
2013-04-16 23:59:02 -04:00
|
|
|
perror(err_msg);
|
|
|
|
fflush(stderr);
|
|
|
|
try_again = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ENOSPC: {
|
2013-04-16 23:59:02 -04:00
|
|
|
if (toku_assert_on_write_enospc) {
|
|
|
|
char err_msg[sizeof("Failed write of [] bytes to fd=[].") + 20+10]; //64 bit is 20 chars, 32 bit is 10 chars
|
2013-04-17 00:00:58 -04:00
|
|
|
snprintf(err_msg, sizeof(err_msg), "Failed write of [%" PRIu64 "] bytes to fd=[%d].", (uint64_t)len, fd);
|
2013-04-16 23:59:02 -04:00
|
|
|
perror(err_msg);
|
2013-04-16 23:58:58 -04:00
|
|
|
fflush(stderr);
|
2013-04-16 23:59:02 -04:00
|
|
|
int out_of_disk_space = 1;
|
|
|
|
assert(!out_of_disk_space); //Give an error message that might be useful if this is the only one that survives.
|
|
|
|
} else {
|
2013-04-16 23:59:57 -04:00
|
|
|
__sync_fetch_and_add(&toku_write_enospc_total, 1);
|
|
|
|
__sync_fetch_and_add(&toku_write_enospc_current, 1);
|
2013-04-16 23:59:02 -04:00
|
|
|
|
|
|
|
time_t tnow = time(0);
|
|
|
|
toku_write_enospc_last_time = tnow;
|
|
|
|
if (toku_write_enospc_last_report == 0 || tnow - toku_write_enospc_last_report >= 60) {
|
|
|
|
toku_write_enospc_last_report = tnow;
|
|
|
|
|
|
|
|
const int tstr_length = 26;
|
|
|
|
char tstr[tstr_length];
|
|
|
|
time_t t = time(0);
|
|
|
|
ctime_r(&t, tstr);
|
|
|
|
|
|
|
|
const int MY_MAX_PATH = 256;
|
2013-04-16 23:59:37 -04:00
|
|
|
char fname[MY_MAX_PATH], symname[MY_MAX_PATH+1];
|
2013-04-16 23:59:02 -04:00
|
|
|
sprintf(fname, "/proc/%d/fd/%d", getpid(), fd);
|
|
|
|
ssize_t n = readlink(fname, symname, MY_MAX_PATH);
|
|
|
|
|
|
|
|
if ((int)n == -1)
|
2013-04-17 00:00:58 -04:00
|
|
|
fprintf(stderr, "%.24s Tokudb No space when writing %" PRIu64 " bytes to fd=%d ", tstr, (uint64_t) len, fd);
|
2013-04-16 23:59:37 -04:00
|
|
|
else {
|
|
|
|
tstr[n] = 0; // readlink doesn't append a NUL to the end of the buffer.
|
2013-04-17 00:00:58 -04:00
|
|
|
fprintf(stderr, "%.24s Tokudb No space when writing %" PRIu64 " bytes to %*s ", tstr, (uint64_t) len, (int) n, symname);
|
2013-04-16 23:59:37 -04:00
|
|
|
}
|
2013-04-16 23:59:02 -04:00
|
|
|
fprintf(stderr, "retry in %d second%s\n", toku_write_enospc_sleep, toku_write_enospc_sleep > 1 ? "s" : "");
|
|
|
|
fflush(stderr);
|
|
|
|
}
|
|
|
|
sleep(toku_write_enospc_sleep);
|
|
|
|
try_again = 1;
|
2013-04-16 23:59:57 -04:00
|
|
|
__sync_fetch_and_sub(&toku_write_enospc_current, 1);
|
2013-04-16 23:59:02 -04:00
|
|
|
break;
|
2013-04-16 23:58:06 -04:00
|
|
|
}
|
2013-04-16 23:59:02 -04:00
|
|
|
}
|
2013-04-16 23:59:02 -04:00
|
|
|
default:
|
|
|
|
break;
|
2013-04-16 23:58:06 -04:00
|
|
|
}
|
2013-04-16 23:58:58 -04:00
|
|
|
assert(try_again);
|
|
|
|
errno = errno_write;
|
2013-04-16 23:58:06 -04:00
|
|
|
}
|
2013-04-16 23:57:38 -04:00
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
static ssize_t (*t_write)(int, const void *, size_t);
|
|
|
|
static ssize_t (*t_full_write)(int, const void *, size_t);
|
|
|
|
static ssize_t (*t_pwrite)(int, const void *, size_t, off_t);
|
|
|
|
static ssize_t (*t_full_pwrite)(int, const void *, size_t, off_t);
|
|
|
|
static FILE * (*t_fdopen)(int, const char *);
|
|
|
|
static FILE * (*t_fopen)(const char *, const char *);
|
|
|
|
static int (*t_open)(const char *, int, int);
|
|
|
|
static int (*t_fclose)(FILE *);
|
|
|
|
static ssize_t (*t_read)(int, void *, size_t);
|
|
|
|
static ssize_t (*t_pread)(int, void *, size_t, off_t);
|
2013-04-16 23:59:11 -04:00
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_write (ssize_t (*write_fun)(int, const void *, size_t)) {
|
2013-04-16 23:59:11 -04:00
|
|
|
t_write = write_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_full_write (ssize_t (*write_fun)(int, const void *, size_t)) {
|
2013-04-16 23:59:11 -04:00
|
|
|
t_full_write = write_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_pwrite (ssize_t (*pwrite_fun)(int, const void *, size_t, off_t)) {
|
2013-04-16 23:57:38 -04:00
|
|
|
t_pwrite = pwrite_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_full_pwrite (ssize_t (*pwrite_fun)(int, const void *, size_t, off_t)) {
|
2013-04-16 23:59:11 -04:00
|
|
|
t_full_pwrite = pwrite_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_fdopen(FILE * (*fdopen_fun)(int, const char *)) {
|
2013-04-16 23:59:13 -04:00
|
|
|
t_fdopen = fdopen_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_fopen(FILE * (*fopen_fun)(const char *, const char *)) {
|
2013-04-16 23:59:13 -04:00
|
|
|
t_fopen = fopen_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_open(int (*open_fun)(const char *, int, int)) {
|
2013-04-16 23:59:13 -04:00
|
|
|
t_open = open_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_fclose(int (*fclose_fun)(FILE*)) {
|
2013-04-16 23:59:13 -04:00
|
|
|
t_fclose = fclose_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_read (ssize_t (*read_fun)(int, void *, size_t)) {
|
2013-04-16 23:59:20 -04:00
|
|
|
t_read = read_fun;
|
|
|
|
}
|
2013-04-16 23:59:11 -04:00
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_pread (ssize_t (*pread_fun)(int, void *, size_t, off_t)) {
|
2013-04-16 23:59:34 -04:00
|
|
|
t_pread = pread_fun;
|
|
|
|
}
|
|
|
|
|
2013-04-16 23:58:55 -04:00
|
|
|
void
|
2013-04-16 23:59:11 -04:00
|
|
|
toku_os_full_write (int fd, const void *buf, size_t len) {
|
2013-04-16 23:59:05 -04:00
|
|
|
const char *bp = (const char *) buf;
|
2013-04-16 23:58:58 -04:00
|
|
|
while (len > 0) {
|
|
|
|
ssize_t r;
|
2013-04-16 23:59:11 -04:00
|
|
|
if (t_full_write) {
|
|
|
|
r = t_full_write(fd, bp, len);
|
2013-04-16 23:58:58 -04:00
|
|
|
} else {
|
2013-04-16 23:59:11 -04:00
|
|
|
r = write(fd, bp, len);
|
2013-04-16 23:58:58 -04:00
|
|
|
}
|
|
|
|
if (r > 0) {
|
|
|
|
len -= r;
|
2013-04-16 23:59:05 -04:00
|
|
|
bp += r;
|
2013-04-16 23:58:58 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
try_again_after_handling_write_error(fd, len, r);
|
|
|
|
}
|
2013-04-16 23:57:38 -04:00
|
|
|
}
|
2013-04-16 23:58:58 -04:00
|
|
|
assert(len == 0);
|
2013-04-16 23:57:38 -04:00
|
|
|
}
|
2013-04-16 23:57:41 -04:00
|
|
|
|
2013-04-16 23:59:11 -04:00
|
|
|
int
|
2013-04-16 23:59:11 -04:00
|
|
|
toku_os_write (int fd, const void *buf, size_t len) {
|
2013-04-16 23:59:11 -04:00
|
|
|
const char *bp = (const char *) buf;
|
|
|
|
int result = 0;
|
|
|
|
while (len > 0) {
|
|
|
|
ssize_t r;
|
2013-04-16 23:59:11 -04:00
|
|
|
if (t_write) {
|
|
|
|
r = t_write(fd, bp, len);
|
2013-04-16 23:59:11 -04:00
|
|
|
} else {
|
2013-04-16 23:59:11 -04:00
|
|
|
r = write(fd, bp, len);
|
2013-04-16 23:59:11 -04:00
|
|
|
}
|
|
|
|
if (r < 0) {
|
|
|
|
result = errno;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
len -= r;
|
|
|
|
bp += r;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-04-16 23:58:55 -04:00
|
|
|
void
|
2013-04-16 23:59:11 -04:00
|
|
|
toku_os_full_pwrite (int fd, const void *buf, size_t len, toku_off_t off) {
|
2013-04-16 23:59:05 -04:00
|
|
|
const char *bp = (const char *) buf;
|
2013-04-16 23:58:58 -04:00
|
|
|
while (len > 0) {
|
|
|
|
ssize_t r;
|
2013-04-16 23:59:11 -04:00
|
|
|
if (t_full_pwrite) {
|
|
|
|
r = t_full_pwrite(fd, bp, len, off);
|
2013-04-16 23:58:58 -04:00
|
|
|
} else {
|
2013-04-16 23:59:11 -04:00
|
|
|
r = pwrite(fd, bp, len, off);
|
2013-04-16 23:58:58 -04:00
|
|
|
}
|
|
|
|
if (r > 0) {
|
|
|
|
len -= r;
|
2013-04-16 23:59:05 -04:00
|
|
|
bp += r;
|
2013-04-16 23:59:11 -04:00
|
|
|
off += r;
|
2013-04-16 23:58:58 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
try_again_after_handling_write_error(fd, len, r);
|
|
|
|
}
|
2013-04-16 23:57:41 -04:00
|
|
|
}
|
2013-04-16 23:58:58 -04:00
|
|
|
assert(len == 0);
|
2013-04-16 23:57:41 -04:00
|
|
|
}
|
2013-04-16 23:57:41 -04:00
|
|
|
|
2013-04-16 23:59:12 -04:00
|
|
|
ssize_t
|
2013-04-16 23:59:11 -04:00
|
|
|
toku_os_pwrite (int fd, const void *buf, size_t len, toku_off_t off) {
|
2013-04-16 23:59:05 -04:00
|
|
|
const char *bp = (const char *) buf;
|
2013-04-16 23:59:12 -04:00
|
|
|
ssize_t result = 0;
|
2013-04-16 23:58:58 -04:00
|
|
|
while (len > 0) {
|
|
|
|
ssize_t r;
|
2013-04-16 23:59:11 -04:00
|
|
|
if (t_pwrite) {
|
|
|
|
r = t_pwrite(fd, bp, len, off);
|
2013-04-16 23:58:58 -04:00
|
|
|
} else {
|
2013-04-16 23:59:11 -04:00
|
|
|
r = pwrite(fd, bp, len, off);
|
2013-04-16 23:58:58 -04:00
|
|
|
}
|
2013-04-16 23:59:11 -04:00
|
|
|
if (r < 0) {
|
|
|
|
result = errno;
|
|
|
|
break;
|
|
|
|
}
|
2013-04-16 23:58:58 -04:00
|
|
|
len -= r;
|
2013-04-16 23:59:05 -04:00
|
|
|
bp += r;
|
2013-04-16 23:59:11 -04:00
|
|
|
off += r;
|
2013-04-16 23:58:58 -04:00
|
|
|
}
|
2013-04-16 23:59:11 -04:00
|
|
|
return result;
|
2013-04-16 23:58:58 -04:00
|
|
|
}
|
|
|
|
|
2013-04-16 23:59:13 -04:00
|
|
|
FILE *
|
|
|
|
toku_os_fdopen(int fildes, const char *mode) {
|
|
|
|
FILE * rval;
|
|
|
|
if (t_fdopen)
|
|
|
|
rval = t_fdopen(fildes, mode);
|
|
|
|
else
|
|
|
|
rval = fdopen(fildes, mode);
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FILE *
|
|
|
|
toku_os_fopen(const char *filename, const char *mode){
|
|
|
|
FILE * rval;
|
|
|
|
if (t_fopen)
|
|
|
|
rval = t_fopen(filename, mode);
|
|
|
|
else
|
|
|
|
rval = fopen(filename, mode);
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
toku_os_open(const char *path, int oflag, int mode) {
|
|
|
|
int rval;
|
|
|
|
if (t_open)
|
|
|
|
rval = t_open(path, oflag, mode);
|
|
|
|
else
|
|
|
|
rval = open(path, oflag, mode);
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
toku_os_fclose(FILE * stream) {
|
|
|
|
int rval = -1;
|
|
|
|
if (t_fclose)
|
|
|
|
rval = t_fclose(stream);
|
|
|
|
else { // if EINTR, retry until success
|
|
|
|
while (rval != 0) {
|
|
|
|
rval = fclose(stream);
|
|
|
|
if (rval && (errno != EINTR))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2013-04-17 00:01:08 -04:00
|
|
|
toku_os_close(int fd) { // if EINTR, retry until success
|
2013-04-16 23:59:13 -04:00
|
|
|
int r = -1;
|
|
|
|
while (r != 0) {
|
|
|
|
r = close(fd);
|
|
|
|
if (r) {
|
|
|
|
int rr = errno;
|
|
|
|
if (rr!=EINTR) printf("rr=%d (%s)\n", rr, strerror(rr));
|
|
|
|
assert(rr==EINTR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
2013-04-16 23:59:11 -04:00
|
|
|
|
2013-04-16 23:59:20 -04:00
|
|
|
ssize_t
|
|
|
|
toku_os_read(int fd, void *buf, size_t count) {
|
|
|
|
ssize_t r;
|
|
|
|
if (t_read)
|
|
|
|
r = t_read(fd, buf, count);
|
|
|
|
else
|
|
|
|
r = read(fd, buf, count);
|
|
|
|
return r;
|
|
|
|
}
|
2013-04-16 23:59:11 -04:00
|
|
|
|
2013-04-16 23:59:34 -04:00
|
|
|
ssize_t
|
|
|
|
toku_os_pread (int fd, void *buf, size_t count, off_t offset) {
|
|
|
|
ssize_t r;
|
|
|
|
if (t_pread) {
|
|
|
|
r = t_pread(fd, buf, count, offset);
|
|
|
|
} else {
|
|
|
|
r = pread(fd, buf, count, offset);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-04-16 23:59:04 -04:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// fsync logic:
|
|
|
|
|
2013-04-16 23:58:53 -04:00
|
|
|
// t_fsync exists for testing purposes only
|
2013-04-16 23:58:52 -04:00
|
|
|
static int (*t_fsync)(int) = 0;
|
2013-04-16 23:58:52 -04:00
|
|
|
static uint64_t toku_fsync_count;
|
|
|
|
static uint64_t toku_fsync_time;
|
2013-04-16 23:58:52 -04:00
|
|
|
|
2013-04-16 23:59:04 -04:00
|
|
|
static uint64_t sched_fsync_count;
|
|
|
|
static uint64_t sched_fsync_time;
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_set_func_fsync(int (*fsync_function)(int)) {
|
2013-04-16 23:58:52 -04:00
|
|
|
t_fsync = fsync_function;
|
2013-04-16 23:59:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// keep trying if fsync fails because of EINTR
|
2013-04-17 00:01:08 -04:00
|
|
|
static void file_fsync_internal (int fd, uint64_t *duration_p) {
|
|
|
|
uint64_t tstart = toku_current_time_usec();
|
2013-04-16 23:58:53 -04:00
|
|
|
int r = -1;
|
|
|
|
while (r != 0) {
|
2013-04-17 00:01:08 -04:00
|
|
|
if (t_fsync) {
|
2013-04-16 23:58:53 -04:00
|
|
|
r = t_fsync(fd);
|
2013-04-17 00:01:08 -04:00
|
|
|
} else {
|
2013-04-16 23:58:53 -04:00
|
|
|
r = fsync(fd);
|
2013-04-17 00:01:08 -04:00
|
|
|
}
|
2013-04-16 23:59:02 -04:00
|
|
|
if (r) {
|
2013-04-17 00:01:08 -04:00
|
|
|
assert(get_error_errno() == EINTR);
|
2013-04-16 23:59:02 -04:00
|
|
|
}
|
2013-04-16 23:58:53 -04:00
|
|
|
}
|
2013-04-16 23:59:57 -04:00
|
|
|
__sync_fetch_and_add(&toku_fsync_count, 1);
|
2013-04-17 00:01:08 -04:00
|
|
|
uint64_t duration = toku_current_time_usec() - tstart;
|
2013-04-16 23:59:57 -04:00
|
|
|
__sync_fetch_and_add(&toku_fsync_time, duration);
|
2013-04-17 00:01:08 -04:00
|
|
|
if (duration_p) {
|
|
|
|
*duration_p = duration;
|
|
|
|
}
|
2013-04-16 23:59:04 -04:00
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_file_fsync_without_accounting(int fd) {
|
|
|
|
file_fsync_internal(fd, NULL);
|
2013-04-16 23:59:02 -04:00
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_fsync_dirfd_without_accounting(DIR *dir) {
|
|
|
|
int fd = dirfd(dir);
|
|
|
|
toku_file_fsync_without_accounting(fd);
|
2013-04-16 23:59:02 -04:00
|
|
|
}
|
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
int toku_fsync_dir_by_name_without_accounting(const char *dir_name) {
|
2013-04-16 23:59:17 -04:00
|
|
|
int r = 0;
|
|
|
|
DIR * dir = opendir(dir_name);
|
|
|
|
if (!dir) {
|
2013-04-17 00:01:08 -04:00
|
|
|
r = get_error_errno();
|
|
|
|
} else {
|
|
|
|
toku_fsync_dirfd_without_accounting(dir);
|
|
|
|
r = closedir(dir);
|
|
|
|
if (r != 0) {
|
|
|
|
r = get_error_errno();
|
2013-04-16 23:59:17 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-04-16 23:59:04 -04:00
|
|
|
// include fsync in scheduling accounting
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_file_fsync(int fd) {
|
2013-04-16 23:59:04 -04:00
|
|
|
uint64_t duration;
|
2013-04-17 00:01:08 -04:00
|
|
|
file_fsync_internal (fd, &duration);
|
2013-04-16 23:59:57 -04:00
|
|
|
__sync_fetch_and_add(&sched_fsync_count, 1);
|
|
|
|
__sync_fetch_and_add(&sched_fsync_time, duration);
|
2013-04-16 23:58:52 -04:00
|
|
|
}
|
2013-04-16 23:58:52 -04:00
|
|
|
|
2013-04-16 23:59:04 -04:00
|
|
|
// for real accounting
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_get_fsync_times(uint64_t *fsync_count, uint64_t *fsync_time) {
|
2013-04-16 23:58:52 -04:00
|
|
|
*fsync_count = toku_fsync_count;
|
|
|
|
*fsync_time = toku_fsync_time;
|
|
|
|
}
|
|
|
|
|
2013-04-16 23:59:04 -04:00
|
|
|
// for scheduling algorithm only
|
2013-04-17 00:01:08 -04:00
|
|
|
void toku_get_fsync_sched(uint64_t *fsync_count, uint64_t *fsync_time) {
|
2013-04-16 23:59:04 -04:00
|
|
|
*fsync_count = sched_fsync_count;
|
|
|
|
*fsync_time = sched_fsync_time;
|
|
|
|
}
|
2013-04-16 23:59:16 -04:00
|
|
|
|
2013-04-17 00:01:08 -04:00
|
|
|
int toku_fsync_directory(const char *fname) {
|
2013-04-16 23:59:16 -04:00
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
// extract dirname from fname
|
2013-04-17 00:00:59 -04:00
|
|
|
const char *sp = strrchr(fname, '/');
|
2013-04-16 23:59:16 -04:00
|
|
|
size_t len;
|
|
|
|
char *dirname = NULL;
|
|
|
|
if (sp) {
|
|
|
|
resource_assert(sp >= fname);
|
|
|
|
len = sp - fname + 1;
|
2013-04-17 00:00:58 -04:00
|
|
|
MALLOC_N(len+1, dirname);
|
2013-04-17 00:01:08 -04:00
|
|
|
if (dirname == NULL) {
|
|
|
|
result = get_error_errno();;
|
|
|
|
} else {
|
2013-04-16 23:59:16 -04:00
|
|
|
strncpy(dirname, fname, len);
|
|
|
|
dirname[len] = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dirname = toku_strdup(".");
|
2013-04-17 00:01:08 -04:00
|
|
|
if (dirname == NULL) {
|
|
|
|
result = get_error_errno();;
|
|
|
|
}
|
2013-04-16 23:59:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (result == 0) {
|
2013-04-16 23:59:17 -04:00
|
|
|
result = toku_fsync_dir_by_name_without_accounting(dirname);
|
2013-04-16 23:59:16 -04:00
|
|
|
}
|
|
|
|
toku_free(dirname);
|
|
|
|
return result;
|
|
|
|
}
|