diff options
-rw-r--r-- | pgfuse.c | 35 | ||||
-rw-r--r-- | pgsql.c | 28 | ||||
-rw-r--r-- | pgsql.h | 1 | ||||
-rw-r--r-- | schema.sql | 2 |
4 files changed, 47 insertions, 19 deletions
@@ -296,6 +296,7 @@ static int pgfuse_create( const char *path, mode_t mode, struct fuse_file_info * meta.ctime = now( ); meta.mtime = meta.ctime; meta.atime = meta.ctime; + meta.ref_count = 1; res = psql_create_file( data->conn, parent_id, path, new_file, meta ); if( res < 0 ) { @@ -303,11 +304,6 @@ static int pgfuse_create( const char *path, mode_t mode, struct fuse_file_info * return res; } - /* get id and store it, remember it in the hash of open files - * the hash function is currently the inode (i.e. the serial - * in the 'id' field module hashtable size, avoiding a much - * more complicated implementation for no good here - */ id = psql_get_meta( data->conn, path, &meta ); if( id < 0 ) { free( copy_path ); @@ -332,6 +328,7 @@ static int pgfuse_open( const char *path, struct fuse_file_info *fi ) PgFuseData *data = (PgFuseData *)fuse_get_context( )->private_data; PgMeta meta; int id; + int res; if( data->verbose ) { char *s = flags_to_string( fi->flags ); @@ -345,6 +342,11 @@ static int pgfuse_open( const char *path, struct fuse_file_info *fi ) return id; } + /* currently don't allow parallel access */ + if( meta.ref_count > 0 ) { + return -ETXTBSY; + } + if( data->verbose ) { syslog( LOG_DEBUG, "Id for file '%s' to open is %d, thread #%d", path, id, fuse_get_context( )->uid ); @@ -362,7 +364,14 @@ static int pgfuse_open( const char *path, struct fuse_file_info *fi ) if( meta.size > MAX_FILE_SIZE ) { return -EFBIG; - } + } + + meta.ref_count = 1; + + res = psql_write_meta( data->conn, id, path, meta ); + if( res < 0 ) { + return res; + } fi->fh = id; @@ -579,6 +588,9 @@ static int pgfuse_fsync( const char *path, int isdatasync, struct fuse_file_info static int pgfuse_release( const char *path, struct fuse_file_info *fi ) { PgFuseData *data = (PgFuseData *)fuse_get_context( )->private_data; + int id; + int res; + PgMeta meta; if( data->verbose ) { syslog( LOG_INFO, "Releasing '%s' on '%s', thread #%d", @@ -592,8 +604,17 @@ static int pgfuse_release( const char *path, struct fuse_file_info *fi ) if( data->read_only ) { return 0; } + + id = psql_get_meta( data->conn, path, &meta ); + if( id < 0 ) { + return id; + } + + meta.ref_count = 0; + + res = psql_write_meta( data->conn, id, path, meta ); - return 0; + return res; } static int pgfuse_write( const char *path, const char *buf, size_t size, @@ -99,7 +99,7 @@ int psql_get_meta( PGconn *conn, const char *path, PgMeta *meta ) int lengths[1] = { strlen( path ) }; int binary[1] = { 1 }; - res = PQexecParams( conn, "SELECT id, size, mode, uid, gid, ctime, mtime, atime FROM dir WHERE path = $1::varchar", + res = PQexecParams( conn, "SELECT id, size, mode, uid, gid, ctime, mtime, atime, ref_count FROM dir WHERE path = $1::varchar", 1, NULL, values, lengths, binary, 1 ); if( PQresultStatus( res ) != PGRES_TUPLES_OK ) { @@ -150,6 +150,10 @@ int psql_get_meta( PGconn *conn, const char *path, PgMeta *meta ) idx = PQfnumber( res, "atime" ); data = PQgetvalue( res, 0, idx ); meta->atime = convert_from_timestamp( *( (uint64_t *)data ) ); + + idx = PQfnumber( res, "ref_count" ); + data = PQgetvalue( res, 0, idx ); + meta->ref_count = ntohl( *( (uint32_t *)data ) ); PQclear( res ); @@ -166,13 +170,14 @@ int psql_write_meta( PGconn *conn, const int id, const char *path, PgMeta meta ) uint64_t param6 = convert_to_timestamp( meta.ctime ); uint64_t param7 = convert_to_timestamp( meta.mtime ); uint64_t param8 = convert_to_timestamp( meta.atime ); - const char *values[8] = { (const char *)¶m1, (const char *)¶m2, (const char *)¶m3, (const char *)¶m4, (const char *)¶m5, (const char *)¶m6, (const char *)¶m7, (const char *)¶m8 }; - int lengths[8] = { sizeof( param1 ), sizeof( param2 ), sizeof( param3 ), sizeof( param4 ), sizeof( param5 ), sizeof( param6 ), sizeof( param7 ), sizeof( param8 ) }; - int binary[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; + int param9 = htonl( meta.ref_count ); + const char *values[9] = { (const char *)¶m1, (const char *)¶m2, (const char *)¶m3, (const char *)¶m4, (const char *)¶m5, (const char *)¶m6, (const char *)¶m7, (const char *)¶m8, (const char *)¶m9 }; + int lengths[9] = { sizeof( param1 ), sizeof( param2 ), sizeof( param3 ), sizeof( param4 ), sizeof( param5 ), sizeof( param6 ), sizeof( param7 ), sizeof( param8 ), sizeof( param9 ) }; + int binary[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; PGresult *res; - res = PQexecParams( conn, "UPDATE dir SET size=$2::int4, mode=$3::int4, uid=$4::int4, gid=$5::int4, ctime=$6::timestamp, mtime=$7::timestamp, atime=$8::timestamp WHERE id=$1::int4", - 8, NULL, values, lengths, binary, 1 ); + res = PQexecParams( conn, "UPDATE dir SET size=$2::int4, mode=$3::int4, uid=$4::int4, gid=$5::int4, ctime=$6::timestamp, mtime=$7::timestamp, atime=$8::timestamp, ref_count=$9::int4 WHERE id=$1::int4", + 9, NULL, values, lengths, binary, 1 ); if( PQresultStatus( res ) != PGRES_COMMAND_OK ) { syslog( LOG_ERR, "Error in psql_write_meta for file '%s': %s", path, PQerrorMessage( conn ) ); @@ -195,13 +200,14 @@ int psql_create_file( PGconn *conn, const int parent_id, const char *path, const uint64_t param6 = convert_to_timestamp( meta.ctime ); uint64_t param7 = convert_to_timestamp( meta.mtime ); uint64_t param8 = convert_to_timestamp( meta.atime ); - const char *values[10] = { (const char *)¶m1, new_file, path, (const char *)¶m2, (const char *)¶m3, (const char *)¶m4, (const char *)¶m5, (const char *)¶m6, (const char *)¶m7, (const char *)¶m8 }; - int lengths[10] = { sizeof( param1 ), strlen( new_file ), strlen( path ), sizeof( param2 ), sizeof( param3 ), sizeof( param4 ), sizeof( param5 ), sizeof( param6 ), sizeof( param7 ), sizeof( param8 ) }; - int binary[10] = { 1, 0, 0, 1, 1, 1, 1, 1, 1, 1 }; + int param9 = htonl( meta.ref_count ); + const char *values[11] = { (const char *)¶m1, new_file, path, (const char *)¶m2, (const char *)¶m3, (const char *)¶m4, (const char *)¶m5, (const char *)¶m6, (const char *)¶m7, (const char *)¶m8, (const char *)¶m9 }; + int lengths[11] = { sizeof( param1 ), strlen( new_file ), strlen( path ), sizeof( param2 ), sizeof( param3 ), sizeof( param4 ), sizeof( param5 ), sizeof( param6 ), sizeof( param7 ), sizeof( param8 ), sizeof( param9 ) }; + int binary[11] = { 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }; PGresult *res; - res = PQexecParams( conn, "INSERT INTO dir( parent_id, name, path, size, mode, uid, gid, ctime, mtime, atime ) VALUES ($1::int4, $2::varchar, $3::varchar, $4::int4, $5::int4, $6::int4, $7::int4, $8::timestamp, $9::timestamp, $10::timestamp )", - 10, NULL, values, lengths, binary, 1 ); + res = PQexecParams( conn, "INSERT INTO dir( parent_id, name, path, size, mode, uid, gid, ctime, mtime, atime, ref_count ) VALUES ($1::int4, $2::varchar, $3::varchar, $4::int4, $5::int4, $6::int4, $7::int4, $8::timestamp, $9::timestamp, $10::timestamp, $11::int4 )", + 11, NULL, values, lengths, binary, 1 ); if( PQresultStatus( res ) != PGRES_COMMAND_OK ) { syslog( LOG_ERR, "Error in psql_create_file for path '%s': %s", @@ -34,6 +34,7 @@ typedef struct PgMeta { struct timespec ctime; /* last status change time */ struct timespec mtime; /* last modification time */ struct timespec atime; /* last access time */ + int ref_count; /* how many open file handles exist for this file */ } PgMeta; int psql_get_meta( PGconn *conn, const char *path, PgMeta *meta ); @@ -9,7 +9,7 @@ CREATE TABLE dir ( mode INTEGER NOT NULL DEFAULT 0, uid INTEGER NOT NULL DEFAULT 0, gid INTEGER NOT NULL DEFAULT 0, - inuse BOOL DEFAULT false, + ref_count INTEGER NOT NULL DEFAULT 0, ctime TIMESTAMP, mtime TIMESTAMP, atime TIMESTAMP |