Alien-Libjio
view release on metacpan or search on metacpan
libjio/libjio/trans.c view on Meta::CPAN
if (fs == NULL)
return NULL;
fs->fd = -1;
fs->jfd = -1;
fs->jdir = NULL;
fs->jdirfd = -1;
fs->jmap = MAP_FAILED;
fs->as_cfg = NULL;
/* we provide either read-only or read-write access, because when we
* commit a transaction we read the current contents before applying,
* and write access is needed for locking with fcntl; the test is done
* this way because O_RDONLY is usually 0, so "if (flags & O_RDONLY)"
* will fail. */
if ((flags & O_WRONLY) || (flags & O_RDWR)) {
flags = flags & ~O_WRONLY;
flags = flags & ~O_RDONLY;
flags = flags | O_RDWR;
} else {
jflags = jflags | J_RDONLY;
}
fs->name = strdup(name);
fs->flags = jflags;
fs->open_flags = flags;
fs->ltrans = NULL;
fs->ltrans_len = 0;
/* Note on fs->lock usage: this lock is used only to protect the file
* pointer. This means that it must only be held while performing
* operations that depend or alter the file pointer (jread, jreadv,
* jwrite, jwritev), but the others (jpread, jpwrite) are left
* unprotected because they can be performed in parallel as long as
* they don't affect the same portion of the file (this is protected
* by lockf). The lock doesn't slow things down tho: any threaded app
* MUST implement this kind of locking anyways if it wants to prevent
* data corruption, we only make it easier for them by taking care of
* it here. If performance is essential, the jpread/jpwrite functions
* should be used, just as real life.
* About fs->ltlock, it's used to protect the lingering transactions
* list, fs->ltrans. */
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
pthread_mutex_init( &(fs->lock), &attr);
pthread_mutex_init( &(fs->ltlock), &attr);
pthread_mutexattr_destroy(&attr);
fs->fd = open(name, flags, mode);
if (fs->fd < 0)
goto error_exit;
/* nothing else to do for read-only access */
if (jflags & J_RDONLY) {
return fs;
}
if (!get_jdir(name, jdir))
goto error_exit;
rv = mkdir(jdir, 0750);
rv = lstat(jdir, &sinfo);
if (rv < 0 || !S_ISDIR(sinfo.st_mode))
goto error_exit;
fs->jdir = (char *) malloc(strlen(jdir) + 1);
if (fs->jdir == NULL)
goto error_exit;
strcpy(fs->jdir, jdir);
/* open the directory, we will use it to flush transaction files'
* metadata in jtrans_commit() */
fs->jdirfd = open(jdir, O_RDONLY);
if (fs->jdirfd < 0)
goto error_exit;
snprintf(jlockfile, PATH_MAX, "%s/lock", jdir);
jfd = open(jlockfile, O_RDWR | O_CREAT, 0600);
if (jfd < 0)
goto error_exit;
fs->jfd = jfd;
/* initialize the lock file by writing the first tid to it, but only
* if its empty, otherwise there is a race if two processes call
* jopen() simultaneously and both initialize the file */
plockf(jfd, F_LOCKW, 0, 0);
lstat(jlockfile, &sinfo);
if (sinfo.st_size != sizeof(unsigned int)) {
t = 0;
rv = spwrite(jfd, &t, sizeof(t), 0);
if (rv != sizeof(t)) {
goto error_exit;
}
}
plockf(jfd, F_UNLOCK, 0, 0);
fs->jmap = (unsigned int *) mmap(NULL, sizeof(unsigned int),
PROT_READ | PROT_WRITE, MAP_SHARED, jfd, 0);
if (fs->jmap == MAP_FAILED)
goto error_exit;
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 NULL;
}
/* Sync a file */
int jsync(struct jfs *fs)
{
int rv;
struct jlinger *ltmp;
if (fs->fd < 0)
return -1;
rv = fdatasync(fs->fd);
if (rv != 0)
return rv;
/* note the jops will be in order, so if we crash or fail in the
* middle of this, there will be no problem applying the remaining
* transactions */
pthread_mutex_lock(&(fs->ltlock));
while (fs->ltrans != NULL) {
fiu_exit_on("jio/jsync/pre_unlink");
if (journal_free(fs->ltrans->jop, 1) != 0) {
pthread_mutex_unlock(&(fs->ltlock));
return -1;
}
ltmp = fs->ltrans->next;
free(fs->ltrans);
fs->ltrans = ltmp;
}
fs->ltrans_len = 0;
pthread_mutex_unlock(&(fs->ltlock));
return 0;
}
/* Change the location of the journal directory */
int jmove_journal(struct jfs *fs, const char *newpath)
( run in 0.801 second using v1.01-cache-2.11-cpan-63c85eba8c4 )