libjio(3)

NAME
libjio - A library for Journaled I/O

SYNOPSIS
#include <libjio.h>
jfs_t *jopen(const char *name, int flags, int mode,
           unsigned int jflags);
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, 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 lenght);
off_t jlseek(jfs_t *fs, off_t offset, int whence);
int jclose(jfs_t *fs);
jtrans_t *jtrans_new(jfs_t *fs, unsigned int flags);
int jtrans_commit(jtrans_t *ts);
int jtrans_add_r(jtrans_t *ts, void *buf,
		size_t count, off_t offset);
int jtrans_add_w(jtrans_t *ts, const void *buf,
		size_t count, off_t offset);
int jtrans_rollback(jtrans_t *ts);
void jtrans_free(jtrans_t *ts);
int jsync(jfs_t *fs);
int jfs_autosync_start(jfs_t *fs, time_t max_sec,
           size_t max_bytes);
int jfs_autosync_stop(jfs_t *fs);
int jmove_journal(jfs_t *fs, const char *newpath);
enum jfsck_return jfsck(const char *name, const char *jdir,
           jfsck_result *res, unsigned int flags);
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 rollbacked;       /* transactions that were rollbacked */
    ...
};
enum jfsck_return {
    J_ESUCCESS = 0,	/* Success */
    J_ENOENT = -1,	/* No such file or directory */
    J_ENOJOURNAL = -2,	/* No journal associated with the given file */
    J_ENOMEM = -3,	/* Not enough free memory */
    J_ECLEANUP = -4,	/* Error cleaning the journal directory */
    J_EIO = -5,		/* I/O error */
};

DESCRIPTION
libjio is a library to do transaction-oriented journaled I/O. This manpage describes its C API very briefly, further information can be found in the documentation that comes along with the library itself, or on the web at http://blitiri.com.ar/p/libjio. Functions can be grouped in three different groups: the common functions, the UNIX-alike API, and the basic functions. All return 0 upon successful completion and < 0 upon failure, unless otherwise noted. The common functions provide functionality common to the other two: jopen() and jclose() to open and close files in order to use them with the library, and jfsck() to provide integrity checking. The UNIX-alike API mimics the traditional UNIX API by providing similar interfaces to read(2), write(2), and friends. The basic functions consist of jtrans_new(), jtrans_add_r(), jtrans_add_w(), jtrans_commit() and jtrans_rollback(). They provide a lower-level method for manipulating transactions.

  TYPES AND STRUCTURES
jfs_t represents an open file, and jtrans_t represents a transaction. Both are meant to be treated as opaque types. struct jfsck_result holds the results of a jfsck() run. The fields are described in the synopsis section.

  COMMON FUNCTIONS
To open a file, you should use jopen(), which is just like the normal open(2) call but returns an opaque pointer. To close a file, use jclose(). They're exactly like the open(2) and close(2) functions but use a jfs_t instead of a file descriptor; take a look at their manpages if you have any doubts about how to use them. jmove_journal() can be used to move the journal directory to a new location. It can be called only when nobody else is using the file. It is usually not used, except for very special cases. jfs_autosync_start() can be used to start a thread which will automatically perform a jsync() after the given number of seconds or the given number of bytes written using lingering transactions (whatever comes first). It's very useful when using lingering transactions. jfs_autosync_stop() stops the thread started by jfs_autosync_start(). The thread is also stopped automatically when jclose() is called. jfsck() takes as the first two parameters the path to the file to check and the path to the journal directory (usually NULL for the default, unless you've changed it manually using jmove_journal()), and optionally a flags parameter, which can be 0 for the default behaviour, or J_CLEANUP to indicate that the journal should be cleaned up after successful recovery. It is used to perform journal checking and recovery in case of a crash. It must be performed when nobody else is using the file (like in the case of a filesystem which can't be mounted), and it returns 0 if success or an error code != 0 in case of a failure. If it succeeded, it will fill jfsck_result summarizing the outcome of the operation. The error codes can be either J_ENOENT (no such file), J_ENOJOURNAL (no journal associated with that file), J_ENOMEM (not enough free memory), J_ECLEANUP (error cleaning the journal directory), and J_EIO (I/O error). There is also a program named jiofsck which is just a simple human frontend to this function.

  UNIX-alike API
The UNIX-alike API, as explained before, consists of the functions jread(), jpread(), jreadv(), jwrite(), jpwrite(), jwritev(), jtruncate()and jlseek(). 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 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.

  BASIC FUNCTIONS
The basic functions are the ones which manipulate transactions directly: jtrans_new(), jtrans_add_r(), jtrans_add_w(), jtrans_commit(), jtrans_rollback() and jtrans_free()". These are intended to be use when your application requires direct control over the transactions. jtrans_new() and jtrans_free() just return a new 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 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 functions. You can add multiple read and write operations to a transaction, and they will be applied in order. jtrans_add_w() is used to add write operations to a transaction, and it takes the same parameters as pwrite(): a buffer, its length and the offset where it should be applied, and adds it to the transaction. The buffer is copied internally and can be free()d right after this function returns. jtrans_add_r() is used to add read operations to a transaction, and it takes the same parameters as pread(): a buffer, its length and the offset where it should read from, and adds it to the transaction. Note that if there is not enough data in the file to read the specified amount of bytes, the commit will fail, so do not attempt to read beyond EOF (you can use jread() for that purpose). jtrans_commit() commits the given transaction to disk. After it has returned, write operations have been saved to the disk, and read operations have been read from it. 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 0 on success, -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). jtrans_rollback() reverses a transaction that was applied with 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 same values as jtrans_commit().

SEE ALSO
open(2), read(2), write(2), readv(2), writev(2), pread(2), pwrite(2), ftruncate(2), lseek(2), close(2)

BUGS
If you want to report bugs, or have any questions or comments, just let me know at albertito@blitiri.com.ar.