author | Alberto Bertogli
<albertito@blitiri.com.ar> 2009-04-15 15:52:45 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2009-04-15 15:52:45 UTC |
parent | cf835d72bd5c0bc050ee26e52d8f5e3ed18f1363 |
UPGRADING | +7 | -2 |
bindings/preload/libjio_preload.c | +13 | -38 |
bindings/python2/libjio.c | +6 | -17 |
bindings/python3/libjio.c | +6 | -17 |
doc/guide.rst | +13 | -12 |
libjio/ansi.c | +6 | -9 |
libjio/check.c | +1 | -2 |
libjio/common.h | +17 | -4 |
libjio/libjio.3 | +53 | -69 |
libjio/libjio.h | +34 | -62 |
libjio/trans.c | +35 | -18 |
libjio/trans.h | +13 | -0 |
libjio/unix.c | +25 | -15 |
samples/full.c | +11 | -11 |
samples/jio1.c | +8 | -5 |
samples/jio2.c | +8 | -5 |
samples/jio3.c | +18 | -11 |
tests/performance/performance.c | +7 | -7 |
tests/performance/random.c | +7 | -7 |
diff --git a/UPGRADING b/UPGRADING index 966e096..7962465 100644 --- a/UPGRADING +++ b/UPGRADING @@ -6,8 +6,13 @@ You should always clean all your files before upgrading. While I don't expect the transaction on-disk format to change, it's a good practise and it doesn't take much effort. When it's mandatory, it will be noted. --> 0.26 - - Applications need to be recompiled due to a change in the jfs structure. +-> 0.50 (Big API change) + - Structures are now opaque types: + struct jfs -> jfs_t; jopen() returns a pointer to one, jclose() frees it. + struct jtrans -> jtrans_t; jtrans_init() returns a pointer to one, + jtrans_free() frees it. + - jtrans_commit() returns -1 on recovered errors, -2 on unrecovered errors + (which are an indication of a severe underlying condition). -> 0.25 - It is no longer necessary to pass O_SYNC to jopen() if lingering diff --git a/bindings/preload/libjio_preload.c b/bindings/preload/libjio_preload.c index d71aa36..2562b81 100644 --- a/bindings/preload/libjio_preload.c +++ b/bindings/preload/libjio_preload.c @@ -66,7 +66,7 @@ static int (*c_dup2)(int oldfd, int newfd); struct fd_entry { int fd; unsigned int *refcount; - struct jfs *fs; + jfs_t *fs; pthread_mutex_t lock; }; static struct fd_entry fd_table[MAXFD]; @@ -200,7 +200,7 @@ static int __attribute__((constructor)) init(void) int open(const char *pathname, int flags, ...) { int r, fd; - struct jfs *fs; + jfs_t *fs; mode_t mode; struct stat st; va_list l; @@ -239,25 +239,14 @@ int open(const char *pathname, int flags, ...) } rec_inc(); - fs = malloc(sizeof(struct jfs)); + fs = jopen(pathname, flags, mode, 0); if (fs == NULL) { rec_dec(); return -1; } - fd = jopen(fs, pathname, flags, mode, 0); - if (fd >= MAXFD) { - printd("too many open fds: %d\n", fd); - jclose(fs); - free(fs); - rec_dec(); - return -1; - } rec_dec(); - if (fd < 0) { - printd("return %d\n", fd); - return fd; - } + fd = jfileno(fs); fd_lock(fd); fd_table[fd].fd = fd; @@ -274,7 +263,7 @@ int open(const char *pathname, int flags, ...) int open64(const char *pathname, int flags, ...) { int r, fd; - struct jfs *fs; + jfs_t *fs; mode_t mode; struct stat st; va_list l; @@ -313,25 +302,14 @@ int open64(const char *pathname, int flags, ...) } rec_inc(); - fs = malloc(sizeof(struct jfs)); + fs = jopen(pathname, flags, mode, 0); if (fs == NULL) { rec_dec(); return -1; } - fd = jopen(fs, pathname, flags, mode, 0); - if (fd >= MAXFD) { - printd("too many open fds: %d\n", fd); - jclose(fs); - free(fs); - rec_dec(); - return -1; - } rec_dec(); - if (fd < 0) { - printd("return %d\n", fd); - return fd; - } + fd = jfileno(fs); fd_lock(fd); fd_table[fd].fd = fd; @@ -366,13 +344,10 @@ int unlocked_close(int fd) r = jclose(fd_table[fd].fs); rec_dec(); - if (fd_table[fd].fs != NULL) { - fd_table[fd].fd = -1; - free(fd_table[fd].refcount); - fd_table[fd].refcount = NULL; - free(fd_table[fd].fs); - fd_table[fd].fs = NULL; - } + fd_table[fd].fd = -1; + free(fd_table[fd].refcount); + fd_table[fd].refcount = NULL; + fd_table[fd].fs = NULL; return r; } @@ -380,7 +355,7 @@ int unlocked_close(int fd) int close(int fd) { int r; - struct jfs *fs; + jfs_t *fs; if (called) { printd("orig\n"); @@ -519,7 +494,7 @@ int dup2(int oldfd, int newfd) rtype name DEF \ { \ rtype r; \ - struct jfs *fs; \ + jfs_t *fs; \ \ if (called) { \ printd("orig\n"); \ diff --git a/bindings/python2/libjio.c b/bindings/python2/libjio.c index 85ce8d1..1e17b14 100644 --- a/bindings/python2/libjio.c +++ b/bindings/python2/libjio.c @@ -39,7 +39,7 @@ /* jfile */ typedef struct { PyObject_HEAD - struct jfs *fs; + jfs_t *fs; } jfile_object; static PyTypeObject jfile_type; @@ -47,7 +47,7 @@ static PyTypeObject jfile_type; /* jtrans */ typedef struct { PyObject_HEAD - struct jtrans *ts; + jtrans_t *ts; jfile_object *jfile; } jtrans_object; @@ -63,7 +63,6 @@ static void jf_dealloc(jfile_object *fp) { if (fp->fs) { jclose(fp->fs); - free(fp->fs); } PyObject_Del(fp); } @@ -79,7 +78,7 @@ static PyObject *jf_fileno(jfile_object *fp, PyObject *args) if (!PyArg_ParseTuple(args, ":fileno")) return NULL; - return PyInt_FromLong(fp->fs->fd); + return PyInt_FromLong(jfileno(fp->fs)); } /* read */ @@ -386,7 +385,7 @@ static PyObject *jf_new_trans(jfile_object *fp, PyObject *args) if (tp == NULL) return NULL; - tp->ts = malloc(sizeof(struct jtrans)); + tp->ts = jtrans_init(fp->fs); if(tp->ts == NULL) { return PyErr_NoMemory(); } @@ -395,8 +394,6 @@ static PyObject *jf_new_trans(jfile_object *fp, PyObject *args) tp->jfile = fp; Py_INCREF(fp); - jtrans_init(fp->fs, tp->ts); - return (PyObject *) tp; } @@ -449,7 +446,6 @@ static void jt_dealloc(jtrans_object *tp) { if (tp->ts != NULL) { jtrans_free(tp->ts); - free(tp->ts); } Py_DECREF(tp->jfile); PyObject_Del(tp); @@ -570,7 +566,6 @@ It's a wrapper to jopen().\n"); static PyObject *jf_open(PyObject *self, PyObject *args) { - int rv; char *file; int flags, mode, jflags; jfile_object *fp; @@ -587,19 +582,13 @@ static PyObject *jf_open(PyObject *self, PyObject *args) if (fp == NULL) return NULL; - fp->fs = malloc(sizeof(struct jfs)); + fp->fs = jopen(file, flags, mode, jflags); if (fp->fs == NULL) { - return PyErr_NoMemory(); - } - - rv = jopen(fp->fs, file, flags, mode, jflags); - if (rv < 0) { - free(fp->fs); return PyErr_SetFromErrno(PyExc_IOError); } if (PyErr_Occurred()) { - free(fp->fs); + jclose(fp->fs); return NULL; } diff --git a/bindings/python3/libjio.c b/bindings/python3/libjio.c index 79e93ce..32e1d41 100644 --- a/bindings/python3/libjio.c +++ b/bindings/python3/libjio.c @@ -39,7 +39,7 @@ /* jfile */ typedef struct { PyObject_HEAD - struct jfs *fs; + jfs_t *fs; } jfile_object; static PyTypeObject jfile_type; @@ -48,7 +48,7 @@ static PyTypeObject jfile_type; /* jtrans */ typedef struct { PyObject_HEAD - struct jtrans *ts; + jtrans_t *ts; jfile_object *jfile; } jtrans_object; @@ -64,7 +64,6 @@ static void jf_dealloc(jfile_object *fp) { if (fp->fs) { jclose(fp->fs); - free(fp->fs); } PyObject_Del(fp); } @@ -80,7 +79,7 @@ static PyObject *jf_fileno(jfile_object *fp, PyObject *args) if (!PyArg_ParseTuple(args, ":fileno")) return NULL; - return PyLong_FromLong(fp->fs->fd); + return PyLong_FromLong(jfileno(fp->fs)); } /* read */ @@ -387,7 +386,7 @@ static PyObject *jf_new_trans(jfile_object *fp, PyObject *args) if (tp == NULL) return NULL; - tp->ts = malloc(sizeof(struct jtrans)); + tp->ts = jtrans_init(fp->fs); if(tp->ts == NULL) { return PyErr_NoMemory(); } @@ -396,8 +395,6 @@ static PyObject *jf_new_trans(jfile_object *fp, PyObject *args) tp->jfile = fp; Py_INCREF(fp); - jtrans_init(fp->fs, tp->ts); - return (PyObject *) tp; } @@ -441,7 +438,6 @@ static void jt_dealloc(jtrans_object *tp) { if (tp->ts != NULL) { jtrans_free(tp->ts); - free(tp->ts); } Py_DECREF(tp->jfile); PyObject_Del(tp); @@ -552,7 +548,6 @@ It's a wrapper to jopen().\n"); static PyObject *jf_open(PyObject *self, PyObject *args) { - int rv; char *file; int flags, mode, jflags; jfile_object *fp; @@ -569,19 +564,13 @@ static PyObject *jf_open(PyObject *self, PyObject *args) if (fp == NULL) return NULL; - fp->fs = malloc(sizeof(struct jfs)); + fp->fs = jopen(file, flags, mode, jflags); if (fp->fs == NULL) { - return PyErr_NoMemory(); - } - - rv = jopen(fp->fs, file, flags, mode, jflags); - if (rv < 0) { - free(fp->fs); return PyErr_SetFromErrno(PyExc_IOError); } if (PyErr_Occurred()) { - free(fp->fs); + jclose(fp->fs); return NULL; } diff --git a/doc/guide.rst b/doc/guide.rst index 3f3bdef..16feac9 100644 --- a/doc/guide.rst +++ b/doc/guide.rst @@ -64,11 +64,10 @@ because they have their own initializer functions, but they are the building blocks for the rest of the text, which, once this is understood, should be obvious and self-evident. -The first structure we face is *struct jfs*, usually called the file -structure, and it represents an open file, just like a regular file descriptor -or a FILE \*. +The first type we face is *jfs_t*, usually called the file structure, and it +represents an open file, just like a regular file descriptor or a FILE \*. -Then you find *struct jtrans*, usually called the transaction structure, which +Then you find *jtrans_t*, usually called the transaction structure, which represents a single transaction. @@ -105,22 +104,24 @@ Let's put it all together and code a nice "hello world" program (return values are ignored for simplicity):: char buf[] = "Hello world!"; - struct jfs file; - struct jtrans trans; + jfs_t *file; + jtrans_t *trans; - jopen(&file, "filename", O_RDWR | O_CREAT, 0600, 0); + file = jopen("filename", O_RDWR | O_CREAT, 0600, 0); - jtrans_init(&file, &trans); - jtrans_add(&trans, buf, strlen(buf), 0); - jtrans_commit(&trans); + trans = jtrans_init(file); + jtrans_add(trans, buf, strlen(buf), 0); + jtrans_commit(trans); + jtrans_free(trans); - jclose(&file); + jclose(file); As we've seen, we open the file and initialize the structure with *jopen()* (with the parameter *jflags* being the last 0), create a new transaction with *jtrans_init()*, then add an operation with *jtrans_add()* (the last 0 is the offset, in this case the beginning of the file), commit the transaction with -*jtrans_commit()*, and finally close the file with *jclose()*. +*jtrans_commit()*, free it with *jtrans_free()*, and finally close the file +with *jclose()*. Reading is much easier: the library provides three functions, *jread()*, *jpread()* and *jreadv()*, that behave exactly like *read()*, *pread()* and diff --git a/libjio/ansi.c b/libjio/ansi.c index 2cc995f..64c9eb8 100644 --- a/libjio/ansi.c +++ b/libjio/ansi.c @@ -16,6 +16,8 @@ #include <pthread.h> #include "libjio.h" +#include "common.h" +#include "trans.h" /* @@ -32,7 +34,6 @@ /* fopen wrapper */ struct jfs *jfopen(const char *path, const char *mode) { - int fd; int flags; int pos_at_the_beginning; struct jfs *fs; @@ -59,18 +60,14 @@ struct jfs *jfopen(const char *path, const char *mode) return NULL; } - fs = malloc(sizeof(struct jfs)); - - fd = jopen(fs, path, flags, 0666, 0); - if (fd < 0) { - free(fs); + fs = jopen(path, flags, 0666, 0); + if (fs == NULL) return NULL; - } if (pos_at_the_beginning) - lseek(fd, 0, SEEK_SET); + lseek(fs->fd, 0, SEEK_SET); else - lseek(fd, 0, SEEK_END); + lseek(fs->fd, 0, SEEK_END); return fs; } diff --git a/libjio/check.c b/libjio/check.c index 35c020f..61a601c 100644 --- a/libjio/check.c +++ b/libjio/check.c @@ -216,13 +216,12 @@ int jfsck(const char *name, const char *jdir, struct jfsck_result *res) /* verify (and possibly fix) all the transactions */ for (i = 1; i <= maxtid; i++) { - curts = malloc(sizeof(struct jtrans)); + curts = jtrans_init(&fs); if (curts == NULL) { ret = J_ENOMEM; goto exit; } - jtrans_init(&fs, curts); curts->id = i; /* open the transaction file, using i as its name, so we are diff --git a/libjio/common.h b/libjio/common.h index 536c514..f5ff8f0 100644 --- a/libjio/common.h +++ b/libjio/common.h @@ -1,9 +1,6 @@ /* - * libjio - A library for Journaled I/O - * Alberto Bertogli (albertito@blitiri.com.ar) - * - * Header for internal functions + * Header for internal functions and definitions */ #ifndef _COMMON_H @@ -29,6 +26,22 @@ #define MAX_TSIZE (SSIZE_MAX) +/* the main file structure */ +struct jfs { + int fd; /* main file descriptor */ + char *name; /* and its name */ + char *jdir; /* journal directory */ + int jdirfd; /* journal directory file descriptor */ + int jfd; /* journal's lock file descriptor */ + unsigned int *jmap; /* journal's lock file mmap area */ + uint32_t flags; /* journal flags */ + struct jlinger *ltrans; /* lingered transactions */ + size_t ltrans_len; /* length of all the lingered transactions */ + pthread_mutex_t ltlock; /* lingered transactions' lock */ + pthread_mutex_t lock; /* a soft lock used in some operations */ + struct autosync_cfg *as_cfg; /* autosync config */ +}; + off_t plockf(int fd, int cmd, off_t offset, off_t len); ssize_t spread(int fd, void *buf, size_t count, off_t offset); diff --git a/libjio/libjio.3 b/libjio/libjio.3 index 3687c32..fde6aad 100644 --- a/libjio/libjio.3 +++ b/libjio/libjio.3 @@ -5,58 +5,49 @@ libjio - A library for Journaled I/O .nf .B #include <libjio.h> -.B struct jfs; - -.BR "struct jtrans " { - ... - unsigned int flags; - ... -}; - -.BR "struct jfsck_result" " {" - int total; /* total transactions files we looked at */ - int invalid; /* invalid files in the journal directory */ - int in_progress; /* transactions in progress */ - int broken; /* transactions broken */ - int apply_error; /* errors applying the transaction */ - int rollbacked; /* transactions that were rollbacked */ - ... -}; - -.BI "int jopen(struct jfs *" fs ", const char *" name "," -.BI " int " flags ", int " mode ", int " jflags ");" -.BI "ssize_t jread(struct jfs *" fs ", void *" buf ", size_t " count ");" -.BI "ssize_t jpread(struct jfs *" fs ", void *" buf ", size_t " count "," +.BI "jfs_t *jopen(const char *" name ", int " flags ", int " mode ", +.BI " int " jflags ");" +.BI "ssize_t jread(jfs_t *" fs ", void *" buf ", size_t " count ");" +.BI "ssize_t jpread(jfs_t *" fs ", void *" buf ", size_t " count "," .BI " off_t " offset ");" -.BI "ssize_t jreadv(struct jfs *" fs ", struct iovec *" vector "," +.BI "ssize_t jreadv(jfs_t *" fs ", struct iovec *" vector "," .BI " int " count ");" -.BI "ssize_t jwrite(struct jfs *" fs ", const void *" buf ", size_t " count ");" -.BI "ssize_t jpwrite(struct jfs *" fs ", const void *" buf ", size_t " count "," +.BI "ssize_t jwrite(jfs_t *" fs ", const void *" buf ", size_t " count ");" +.BI "ssize_t jpwrite(jfs_t *" fs ", const void *" buf ", size_t " count "," .BI " off_t " offset ");" -.BI "ssize_t jwritev(struct jfs *" fs ", const struct iovec *" vector "," +.BI "ssize_t jwritev(jfs_t *" fs ", const struct iovec *" vector "," .BI " int " count ");" -.BI "int jtruncate(struct jfs *" fs ", off_t " lenght ");" -.BI "off_t jlseek(struct jfs *" fs ", off_t " offset ", int " whence ");" -.BI "int jclose(struct jfs *" fs ");" +.BI "int jtruncate(jfs_t *" fs ", off_t " lenght ");" +.BI "off_t jlseek(jfs_t *" fs ", off_t " offset ", int " whence ");" +.BI "int jclose(jfs_t *" fs ");" -.BI "void jtrans_init(struct jfs *" fs " ,struct jtrans *" ts ");" -.BI "int jtrans_commit(struct jtrans *" ts ");" -.BI "int jtrans_add(struct jtrans *" ts ", const void * " buf "," +.BI "jtrans_t *jtrans_init(jfs_t *" fs ");" +.BI "int jtrans_commit(jtrans_t *" ts ");" +.BI "int jtrans_add(jtrans_t *" ts ", const void *" buf "," .BI " size_t " count ", off_t " offset ");" -.BI "int jtrans_rollback(struct jtrans *" ts ");" -.BI "void jtrans_free(struct jtrans *" ts ");" +.BI "int jtrans_rollback(jtrans_t *" ts ");" +.BI "void jtrans_free(jtrans_t *" ts ");" -.BI "int jsync(struct jfs *" fs ");" -.BI "int jmove_journal(struct jfs *" fs ", const char *" newpath ");" -.BI "int jfs_autosync_start(struct jfs *" fs ", time_t " max_sec "," +.BI "int jsync(jfs_t *" fs ");" +.BI "int jfs_autosync_start(jfs_t *" fs ", time_t " max_sec "," .BI " size_t " max_bytes ");" -.BI "int jfs_autosync_stop(struct jfs *" fs ");" - +.BI "int jfs_autosync_stop(jfs_t *" fs ");" +.BI "int jmove_journal(jfs_t *" fs ", const char *" newpath ");" .BI "int jfsck(const char *" name ", const char *" jdir "," -.BI " struct jfsck_result *" res ");" +.BI " jfs_tck_result *" res ");" .BI "int jfsck_cleanup(const char *" name ", const char *" jdir ");" +.BR "struct jfsck_result" " {" + int total; /* total transactions files we looked at */ + int invalid; /* invalid files in the journal directory */ + int in_progress; /* transactions in progress */ + int broken; /* transactions broken */ + int apply_error; /* errors applying the transaction */ + int rollbacked; /* transactions that were rollbacked */ + ... +}; + .SH DESCRIPTION libjio is a library to do transaction-oriented journaled I/O. This manpage @@ -82,39 +73,33 @@ and friends. The basic functions consist of .BR jtrans_init() ", " jtrans_add() ", " jtrans_commit() " and " .BR jtrans_rollback() . -They provide a lower-level method for manipulating transactions, which are -defined in the -.IR "jtrans structure" . +They provide a lower-level method for manipulating transactions. -.SS STRUCTURES +.SS TYPES AND STRUCTURES -Both -.IR "struct jfs" " and " "struct jtrans" -are meant to be treated as opaque types, except for the fields documented -above, which you should treat as read-only. +.I jfs_t +represents an open file, and +.I jtrans_t +represents a transaction. Both are meant to be treated as opaque types. .B struct jfsck_result holds the results of a .B jfsck() -run, see below for details. +run. The fields are described in the synopsis section. .SS COMMON FUNCTIONS -Most functions reference the structures described above, specially -.IR "struct jfs" " and " "struct jtrans" . -They represent, respectively, a file to operate on and a single transaction. To open a file, you should use .BR jopen() , which is just like the normal .B open(2) -call but affects a pointer to a -.IR struct jfs . +call but returns an opaque pointer. To close a file, use .BR jclose() . They're exactly like the .BR open(2) " and " close(2) functions but use a -.I struct jfs +.I jfs_t instead of a file descriptor; take a look at their manpages if you have any doubts about how to use them. @@ -184,7 +169,7 @@ The UNIX-alike API, as explained before, consists of the functions They are all exactly like the UNIX equivalent, and behave the same way, with the only exception that instead of a file descriptor you need to pass a pointer to a -.IR "struct jfs" . +.IR "jfs_t" . Again, I will not duplicate the manpage for all these functions, just refer to the regular UNIX versions to see how to use them, they all have the same semantics and behave the same way. @@ -199,9 +184,10 @@ These are intended to be use when your application requires direct control over the transactions. .BR jtrans_init() " and " jtrans_free() -just initialize and free a given transaction structure; the former should be -called prior any use, and the latter when you want to destroy a transaction. -Note that +just return a new +.I jtrans_t +and free a given one; the former should be called prior any use, and the +latter when you want to destroy a transaction. Note that .B jtrans_free() is not a disk operation, but only frees the pointers that were previously allocated by the library; all disk operations are performed by the other two @@ -217,22 +203,20 @@ will be applied in order. .B jtrans_commit() commits the given transaction to disk. After it has returned, data has been -saved to the disk. It returns the number of bytes written or -1 if there was -an error. On an error, the -.B flags -field of the -.B jtrans -structure will have the J_ROLLBACKED set if the transaction was successfuly -rollbacked. The commit operation is atomic with regards to other read or write -operations on different processes, as long as they all access it via libjio. +saved to the disk. The commit operation is atomic with regards to other read +or write operations on different processes, as long as they all access it via +libjio. It returns the number of bytes written, -1 if there was an error but +atomic warantees were preserved, or -2 if there was an error and there is a +possible break of atomic warantees (which is an indication of a severe +underlying condition). .B jtrans_rollback() reverses a transaction that was applied with .BR jtrans_commit() , and leaves the file as it was before applying it. Be very very careful with this function, it's quite dangerous if you don't know for sure that you're -doing the right thing. It returns the number of bytes written or -1 if there -was an error. +doing the right thing. It returns the same values as +.BR jtrans_commit() . .SH SEE ALSO diff --git a/libjio/libjio.h b/libjio/libjio.h index 8819159..1c295b4 100644 --- a/libjio/libjio.h +++ b/libjio/libjio.h @@ -24,36 +24,8 @@ #endif /* empty declarations, the API does not expose these */ -struct jlinger; -struct joper; -struct autosync_cfg; - -/* the main file structure */ -struct jfs { - int fd; /* main file descriptor */ - char *name; /* and its name */ - char *jdir; /* journal directory */ - int jdirfd; /* journal directory file descriptor */ - int jfd; /* journal's lock file descriptor */ - unsigned int *jmap; /* journal's lock file mmap area */ - uint32_t flags; /* journal flags */ - struct jlinger *ltrans; /* lingered transactions */ - size_t ltrans_len; /* length of all the lingered transactions */ - pthread_mutex_t ltlock; /* lingered transactions' lock */ - pthread_mutex_t lock; /* a soft lock used in some operations */ - struct autosync_cfg *as_cfg; /* autosync config */ -}; - -/* a transaction */ -struct jtrans { - struct jfs *fs; /* journal file structure to operate on */ - int id; /* transaction id */ - uint32_t flags; /* transaction flags */ - unsigned int numops; /* quantity of operations in the list */ - size_t len; /* transaction's length */ - pthread_mutex_t lock; /* used to modify the operation list */ - struct joper *op; /* list of operations */ -}; +typedef struct jfs jfs_t; +typedef struct jtrans jtrans_t; struct jfsck_result { int total; /* total transactions files we looked at */ @@ -67,19 +39,19 @@ struct jfsck_result { /* core functions */ -int jopen(struct jfs *fs, const char *name, int flags, int mode, int jflags); -void jtrans_init(struct jfs *fs, struct jtrans *ts); -int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset); -ssize_t jtrans_commit(struct jtrans *ts); -ssize_t jtrans_rollback(struct jtrans *ts); -void jtrans_free(struct jtrans *ts); -int jsync(struct jfs *fs); -int jmove_journal(struct jfs *fs, const char *newpath); -int jclose(struct jfs *fs); +jfs_t *jopen(const char *name, int flags, int mode, int jflags); +jtrans_t *jtrans_init(jfs_t *fs); +int jtrans_add(jtrans_t *ts, const void *buf, size_t count, off_t offset); +ssize_t jtrans_commit(jtrans_t *ts); +ssize_t jtrans_rollback(jtrans_t *ts); +void jtrans_free(jtrans_t *ts); +int jsync(jfs_t *fs); +int jmove_journal(jfs_t *fs, const char *newpath); +int jclose(jfs_t *fs); /* autosync */ -int jfs_autosync_start(struct jfs *fs, time_t max_sec, size_t max_bytes); -int jfs_autosync_stop(struct jfs *fs); +int jfs_autosync_start(jfs_t *fs, time_t max_sec, size_t max_bytes); +int jfs_autosync_stop(jfs_t *fs); /* journal checker */ @@ -87,29 +59,29 @@ int jfsck(const char *name, const char *jdir, struct jfsck_result *res); int jfsck_cleanup(const char *name, const char *jdir); /* UNIX API wrappers */ -ssize_t jread(struct jfs *fs, void *buf, size_t count); -ssize_t jpread(struct jfs *fs, void *buf, size_t count, off_t offset); -ssize_t jreadv(struct jfs *fs, const struct iovec *vector, int count); -ssize_t jwrite(struct jfs *fs, const void *buf, size_t count); -ssize_t jpwrite(struct jfs *fs, const void *buf, size_t count, off_t offset); -ssize_t jwritev(struct jfs *fs, const struct iovec *vector, int count); -int jtruncate(struct jfs *fs, off_t length); -off_t jlseek(struct jfs *fs, off_t offset, int whence); +ssize_t jread(jfs_t *fs, void *buf, size_t count); +ssize_t jpread(jfs_t *fs, void *buf, size_t count, off_t offset); +ssize_t jreadv(jfs_t *fs, const struct iovec *vector, int count); +ssize_t jwrite(jfs_t *fs, const void *buf, size_t count); +ssize_t jpwrite(jfs_t *fs, const void *buf, size_t count, off_t offset); +ssize_t jwritev(jfs_t *fs, const struct iovec *vector, int count); +int jtruncate(jfs_t *fs, off_t length); +off_t jlseek(jfs_t *fs, off_t offset, int whence); /* ANSI C stdio wrappers */ -struct jfs *jfopen(const char *path, const char *mode); -int jfclose(struct jfs *stream); -struct jfs *jfreopen(const char *path, const char *mode, struct jfs *stream); -size_t jfread(void *ptr, size_t size, size_t nmemb, struct jfs *stream); -size_t jfwrite(const void *ptr, size_t size, size_t nmemb, struct jfs *stream); -int jfileno(struct jfs *stream); -int jfeof(struct jfs *stream); -void jclearerr(struct jfs *stream); -int jferror(struct jfs *stream); -int jfseek(struct jfs *stream, long offset, int whence); -long jftell(struct jfs *stream); -void jrewind(struct jfs *stream); -FILE *jfsopen(struct jfs *stream, const char *mode); +jfs_t *jfopen(const char *path, const char *mode); +int jfclose(jfs_t *stream); +jfs_t *jfreopen(const char *path, const char *mode, jfs_t *stream); +size_t jfread(void *ptr, size_t size, size_t nmemb, jfs_t *stream); +size_t jfwrite(const void *ptr, size_t size, size_t nmemb, jfs_t *stream); +int jfileno(jfs_t *stream); +int jfeof(jfs_t *stream); +void jclearerr(jfs_t *stream); +int jferror(jfs_t *stream); +int jfseek(jfs_t *stream, long offset, int whence); +long jftell(jfs_t *stream); +void jrewind(jfs_t *stream); +FILE *jfsopen(jfs_t *stream, const char *mode); /* jfs and jtrans constants */ diff --git a/libjio/trans.c b/libjio/trans.c index 34bb33c..0053aea 100644 --- a/libjio/trans.c +++ b/libjio/trans.c @@ -31,9 +31,14 @@ */ /* initialize a transaction structure */ -void jtrans_init(struct jfs *fs, struct jtrans *ts) +struct jtrans *jtrans_init(struct jfs *fs) { pthread_mutexattr_t attr; + struct jtrans *ts; + + ts = malloc(sizeof(struct jtrans)); + if (ts == NULL) + return NULL; ts->fs = fs; ts->id = 0; @@ -45,6 +50,8 @@ void jtrans_init(struct jfs *fs, struct jtrans *ts) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); pthread_mutex_init( &(ts->lock), &attr); pthread_mutexattr_destroy(&attr); + + return ts; } @@ -67,6 +74,8 @@ void jtrans_free(struct jtrans *ts) ts->op = tmpop; } pthread_mutex_destroy(&(ts->lock)); + + free(ts); } @@ -259,8 +268,7 @@ rollback_exit: * never appear), so we remove the transaction file (see unlink_exit). * * Transactions that were successfuly recovered by rolling them back - * will have J_ROLLBACKED in their flags, so the caller can verify if - * the failure was recovered or not. */ + * will have J_ROLLBACKED in their flags */ if (!(ts->flags & J_COMMITTED) && !(ts->flags & J_ROLLBACKING)) { rv = ts->flags; ts->flags = ts->flags | J_NOLOCK | J_ROLLBACKING; @@ -294,20 +302,22 @@ exit: /* return the length only if it was properly committed */ if (ts->flags & J_COMMITTED) return written; - else + else if (ts->flags & J_ROLLBACKED) return -1; + else + return -2; } /* rollback a transaction */ ssize_t jtrans_rollback(struct jtrans *ts) { ssize_t rv; - struct jtrans newts; + struct jtrans *newts; struct joper *op, *curop, *lop; - jtrans_init(ts->fs, &newts); - newts.flags = ts->flags; - newts.numops = ts->numops; + newts = jtrans_init(ts->fs); + newts->flags = ts->flags; + newts->numops = ts->numops; if (ts->op == NULL || ts->flags & J_NOROLLBACK) { rv = -1; @@ -348,12 +358,12 @@ ssize_t jtrans_rollback(struct jtrans *ts) curop->locked = 0; /* add the new transaction to the list */ - if (newts.op == NULL) { - newts.op = curop; + if (newts->op == NULL) { + newts->op = curop; curop->prev = NULL; curop->next = NULL; } else { - for (lop = newts.op; lop->next != NULL; lop = lop->next) + for (lop = newts->op; lop->next != NULL; lop = lop->next) ; lop->next = curop; curop->prev = lop; @@ -361,15 +371,15 @@ ssize_t jtrans_rollback(struct jtrans *ts) } } - rv = jtrans_commit(&newts); + rv = jtrans_commit(newts); exit: /* free the transaction */ - for (curop = newts.op; curop != NULL; curop = curop->next) { + for (curop = newts->op; curop != NULL; curop = curop->next) { curop->buf = NULL; curop->pdata = NULL; } - jtrans_free(&newts); + jtrans_free(newts); return rv; } @@ -379,13 +389,18 @@ exit: */ /* open a file */ -int jopen(struct jfs *fs, const char *name, int flags, int mode, int jflags) +struct jfs *jopen(const char *name, int flags, int mode, int jflags) { int jfd, rv; unsigned int t; char jdir[PATH_MAX], jlockfile[PATH_MAX]; struct stat sinfo; pthread_mutexattr_t attr; + struct jfs *fs; + + fs = malloc(sizeof(struct jfs)); + if (fs == NULL) + return NULL; fs->fd = -1; fs->jfd = -1; @@ -437,7 +452,7 @@ int jopen(struct jfs *fs, const char *name, int flags, int mode, int jflags) /* nothing else to do for read-only access */ if (jflags & J_RDONLY) { - return fs->fd; + return fs; } if (!get_jdir(name, jdir)) @@ -485,14 +500,14 @@ int jopen(struct jfs *fs, const char *name, int flags, int mode, int jflags) if (fs->jmap == MAP_FAILED) goto error_exit; - return fs->fd; + return fs; error_exit: /* if there was an error, clean up as much as possible so we don't * leak anything, and return failure; jclose just does this cleaning * for us */ jclose(fs); - return -1; + return NULL; } /* sync a file (makes sense only if using lingering transactions) */ @@ -615,6 +630,8 @@ int jclose(struct jfs *fs) free(fs->jdir); pthread_mutex_destroy(&(fs->lock)); + free(fs); + return ret; } diff --git a/libjio/trans.h b/libjio/trans.h index 94ae9b7..05c22b4 100644 --- a/libjio/trans.h +++ b/libjio/trans.h @@ -3,6 +3,19 @@ #define _TRANS_H +struct joper; + +/* a transaction */ +struct jtrans { + struct jfs *fs; /* journal file structure to operate on */ + int id; /* transaction id */ + uint32_t flags; /* transaction flags */ + unsigned int numops; /* quantity of operations in the list */ + size_t len; /* transaction's length */ + pthread_mutex_t lock; /* used to modify the operation list */ + struct joper *op; /* list of operations */ +}; + /* a single operation */ struct joper { int locked; /* is the region is locked? */ diff --git a/libjio/unix.c b/libjio/unix.c index a2d8e9e..3182124 100644 --- a/libjio/unix.c +++ b/libjio/unix.c @@ -13,6 +13,7 @@ #include "libjio.h" #include "common.h" +#include "trans.h" /* read() family wrappers */ @@ -82,15 +83,18 @@ ssize_t jwrite(struct jfs *fs, const void *buf, size_t count) { int rv; off_t pos; - struct jtrans ts; + struct jtrans *ts; + + ts = jtrans_init(fs); + if (ts == NULL) + return -1; pthread_mutex_lock(&(fs->lock)); - jtrans_init(fs, &ts); pos = lseek(fs->fd, 0, SEEK_CUR); - jtrans_add(&ts, buf, count, pos); + jtrans_add(ts, buf, count, pos); - rv = jtrans_commit(&ts); + rv = jtrans_commit(ts); if (rv > 0) { /* if success, advance the file pointer */ @@ -99,7 +103,7 @@ ssize_t jwrite(struct jfs *fs, const void *buf, size_t count) pthread_mutex_unlock(&(fs->lock)); - jtrans_free(&ts); + jtrans_free(ts); return rv; } @@ -108,14 +112,17 @@ ssize_t jwrite(struct jfs *fs, const void *buf, size_t count) ssize_t jpwrite(struct jfs *fs, const void *buf, size_t count, off_t offset) { int rv; - struct jtrans ts; + struct jtrans *ts; + + ts = jtrans_init(fs); + if (ts == NULL) + return -1; - jtrans_init(fs, &ts); - jtrans_add(&ts, buf, count, offset); + jtrans_add(ts, buf, count, offset); - rv = jtrans_commit(&ts); + rv = jtrans_commit(ts); - jtrans_free(&ts); + jtrans_free(ts); return rv; } @@ -126,22 +133,25 @@ ssize_t jwritev(struct jfs *fs, const struct iovec *vector, int count) int rv, i; size_t sum; off_t ipos, t; - struct jtrans ts; + struct jtrans *ts; + + ts = jtrans_init(fs); + if (ts == NULL) + return -1; pthread_mutex_lock(&(fs->lock)); - jtrans_init(fs, &ts); ipos = lseek(fs->fd, 0, SEEK_CUR); t = ipos; sum = 0; for (i = 0; i < count; i++) { - jtrans_add(&ts, vector[i].iov_base, vector[i].iov_len, t); + jtrans_add(ts, vector[i].iov_base, vector[i].iov_len, t); sum += vector[i].iov_len; t += vector[i].iov_len; } - rv = jtrans_commit(&ts); + rv = jtrans_commit(ts); if (rv > 0) { /* if success, advance the file pointer */ @@ -150,7 +160,7 @@ ssize_t jwritev(struct jfs *fs, const struct iovec *vector, int count) pthread_mutex_unlock(&(fs->lock)); - jtrans_free(&ts); + jtrans_free(ts); return rv; diff --git a/samples/full.c b/samples/full.c index 83e069c..e36f0f2 100644 --- a/samples/full.c +++ b/samples/full.c @@ -12,8 +12,8 @@ int main(void) { int r; - struct jfs file; - struct jtrans trans; + jfs_t *file; + struct jtrans *trans; struct jfsck_result result; /* check the file is OK */ @@ -21,17 +21,17 @@ int main(void) jfsck_cleanup(FILENAME, NULL); /* and open it */ - r = jopen(&file, FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0600, 0); - if (r < 0) { + file = jopen(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0600, 0); + if (file == NULL) { perror("jopen"); return 1; } /* write two "Hello world"s next to each other */ - jtrans_init(&file, &trans); - jtrans_add(&trans, TEXT, strlen(TEXT), 0); - jtrans_add(&trans, TEXT, strlen(TEXT), strlen(TEXT)); - r = jtrans_commit(&trans); + trans = jtrans_init(file); + jtrans_add(trans, TEXT, strlen(TEXT), 0); + jtrans_add(trans, TEXT, strlen(TEXT), strlen(TEXT)); + r = jtrans_commit(trans); if (r < 0) { perror("jtrans_commit"); return 1; @@ -40,7 +40,7 @@ int main(void) /* at this point the file has "Hello world!\nHello world!\n" */ /* now we rollback */ - r = jtrans_rollback(&trans); + r = jtrans_rollback(trans); if (r < 0) { perror("jtrans_rollback"); return 1; @@ -48,8 +48,8 @@ int main(void) /* and now the file is empty! */ - jtrans_free(&trans); - jclose(&file); + jtrans_free(trans); + jclose(file); return 0; } diff --git a/samples/jio1.c b/samples/jio1.c index 9fb4062..d45901f 100644 --- a/samples/jio1.c +++ b/samples/jio1.c @@ -12,17 +12,20 @@ static int jio(void) { - int fd, rv; - struct jfs fs; + int rv; + jfs_t *fs; - fd = jopen(&fs, "test1", O_RDWR | O_CREAT | O_TRUNC, 0660, 0); - if (fd < 0) + fs = jopen("test1", O_RDWR | O_CREAT | O_TRUNC, 0660, 0); + if (fs == NULL) perror("jopen()"); - rv = jwrite(&fs, STR, strlen(STR)); + rv = jwrite(fs, STR, strlen(STR)); if (rv != strlen(STR)) perror("jwrite()"); + if (jclose(fs)) + perror("jclose()"); + return 0; } diff --git a/samples/jio2.c b/samples/jio2.c index 3296dab..e720630 100644 --- a/samples/jio2.c +++ b/samples/jio2.c @@ -14,17 +14,20 @@ static int jio(void) { - int fd, rv; - struct jfs fs; + int rv; + jfs_t *fs; - fd = jopen(&fs, "test2", O_RDWR | O_CREAT | O_TRUNC, 0660, 0); - if (fd < 0) + fs = jopen("test2", O_RDWR | O_CREAT | O_TRUNC, 0660, 0); + if (fs == NULL) perror("jopen()"); - rv = jwrite(&fs, STR, strlen(STR)); + rv = jwrite(fs, STR, strlen(STR)); if (rv != strlen(STR)) perror("jwrite()"); + if (jclose(fs)) + perror("jclose()"); + return 0; } diff --git a/samples/jio3.c b/samples/jio3.c index d66ee8d..88a68d4 100644 --- a/samples/jio3.c +++ b/samples/jio3.c @@ -11,35 +11,42 @@ int main(int argc, char **argv) { - int fd, rv; - struct jfs fs; - struct jtrans ts; + int rv; + jfs_t *fs; + jtrans_t *ts; - fd = jopen(&fs, "test3", O_RDWR | O_CREAT, 0660, 0); - if (fd < 0) + fs = jopen("test3", O_RDWR | O_CREAT, 0660, 0); + if (fs == NULL) perror("jopen()"); - jtrans_init(&fs, &ts); + ts = jtrans_init(fs); + if (ts == NULL) + perror("jtrans_init()"); #define str1 "1ROLLBACKTEST1!\n" - jtrans_add(&ts, str1, strlen(str1), 0); + jtrans_add(ts, str1, strlen(str1), 0); #define str2 "2ROLLBACKTEST2!\n" - jtrans_add(&ts, str2, strlen(str2), strlen(str1)); + jtrans_add(ts, str2, strlen(str2), strlen(str1)); #define str3 "3ROLLBACKTEST3!\n" - jtrans_add(&ts, str3, strlen(str3), strlen(str1) + strlen(str2)); + jtrans_add(ts, str3, strlen(str3), strlen(str1) + strlen(str2)); - rv = jtrans_commit(&ts); + rv = jtrans_commit(ts); if (rv != strlen(str1) + strlen(str2) + strlen(str3)) perror("jtrans_commit()"); printf("commit ok: %d\n", rv); - rv = jtrans_rollback(&ts); + rv = jtrans_rollback(ts); if (rv < 0) perror("jtrans_rollback()"); printf("rollback ok: %d\n", rv); + jtrans_free(ts); + + if (jclose(fs)) + perror("jclose()"); + return 0; } diff --git a/tests/performance/performance.c b/tests/performance/performance.c index 789b966..a2c48bc 100644 --- a/tests/performance/performance.c +++ b/tests/performance/performance.c @@ -21,7 +21,7 @@ #define FILENAME "test_file" /* These are shared among threads, to make the code simpler */ -static struct jfs fs; +static jfs_t *fs; static unsigned long mb; static ssize_t blocksize, towrite; @@ -61,7 +61,7 @@ static void *worker(void *tno) gettimeofday(&tv1, NULL); while (work_done < towrite) { - rv = jpwrite(&fs, buf, blocksize, localoffset + work_done); + rv = jpwrite(fs, buf, blocksize, localoffset + work_done); if (rv != blocksize) { perror("jpwrite()"); break; @@ -92,7 +92,7 @@ static void *worker(void *tno) int main(int argc, char **argv) { - int rv, nthreads; + int nthreads; unsigned long i; pthread_t *threads; struct jfsck_result ckres; @@ -113,13 +113,13 @@ int main(int argc, char **argv) return 1; } - rv = jopen(&fs, FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0600, 0); - if (rv < 0) { + fs = jopen(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0600, 0); + if (fs == NULL) { perror("jopen()"); return 1; } - jtruncate(&fs, towrite * nthreads); + jtruncate(fs, towrite * nthreads); for (i = 0; i < nthreads; i++) { pthread_create(threads + i, NULL, &worker, (void *) i); @@ -129,7 +129,7 @@ int main(int argc, char **argv) pthread_join(*(threads + i), NULL); } - jclose(&fs); + jclose(fs); jfsck(FILENAME, NULL, &ckres); if (ckres.total != 0) { fprintf(stderr, "There were %d errors during the test\n", diff --git a/tests/performance/random.c b/tests/performance/random.c index b159952..b21ba27 100644 --- a/tests/performance/random.c +++ b/tests/performance/random.c @@ -21,7 +21,7 @@ #define FILENAME "test_file" /* These are shared among threads, to make the code simpler */ -static struct jfs fs; +static jfs_t *fs; static unsigned long mb; static ssize_t blocksize, towrite; @@ -64,7 +64,7 @@ static void *worker(void *tno) while (work_done < towrite) { offset = random() % (towrite - blocksize); - rv = jpwrite(&fs, buf, blocksize, localoffset + offset); + rv = jpwrite(fs, buf, blocksize, localoffset + offset); if (rv != blocksize) { perror("jpwrite()"); break; @@ -95,7 +95,7 @@ static void *worker(void *tno) int main(int argc, char **argv) { - int rv, nthreads; + int nthreads; unsigned long i; pthread_t *threads; struct jfsck_result ckres; @@ -116,13 +116,13 @@ int main(int argc, char **argv) return 1; } - rv = jopen(&fs, FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0600, 0); - if (rv < 0) { + fs = jopen(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0600, 0); + if (fs == NULL) { perror("jopen()"); return 1; } - jtruncate(&fs, towrite * nthreads); + jtruncate(fs, towrite * nthreads); for (i = 0; i < nthreads; i++) { pthread_create(threads + i, NULL, &worker, (void *) i); @@ -132,7 +132,7 @@ int main(int argc, char **argv) pthread_join(*(threads + i), NULL); } - jclose(&fs); + jclose(fs); jfsck(FILENAME, NULL, &ckres); if (ckres.total != 0) { fprintf(stderr, "There were %d errors during the test\n",