working open+read+flush+release
authorTero Marttila <terom@fixme.fi>
Thu, 16 Oct 2008 22:56:29 +0300
changeset 30 d8fabd347a8e
parent 29 5de62ca9a5aa
child 31 7804cd7b5cd5
working open+read+flush+release
Makefile
src/dbfs.c
src/dbfs.h
src/dbfs/common.c
src/dbfs/core.c
src/dbfs/dbfs.c
src/dbfs/dirop.c
src/dbfs/fileop.c
src/dbfs/op_base.h
src/dbfs/ops.h
src/evsql.h
src/evsql/util.c
--- a/Makefile	Thu Oct 16 22:04:53 2008 +0300
+++ b/Makefile	Thu Oct 16 22:56:29 2008 +0300
@@ -19,8 +19,8 @@
 BIN_PATHS = $(addprefix bin/,$(BIN_NAMES))
 
 # complex modules
-EVSQL_OBJS = obj/evsql.o obj/evsql_util.o obj/evpq.o
-DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/dirop.o obj/dirbuf.o
+EVSQL_OBJS = obj/evsql/evsql.o obj/evsql/util.o obj/evpq.o
+DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/dirop.o obj/dirbuf.o obj/dbfs/fileop.o
 
 # first target
 all: ${BIN_PATHS}
--- a/src/dbfs.c	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs.c	Thu Oct 16 22:56:29 2008 +0300
@@ -38,8 +38,8 @@
         ERROR("signals_default");
 
     // setup dbfs
-    if ((ctx = dbfs_open(ev_base, &fuse_args, db_conninfo)) == NULL)
-        ERROR("dbfs_open");
+    if ((ctx = dbfs_new(ev_base, &fuse_args, db_conninfo)) == NULL)
+        ERROR("dbfs_new");
 
     // run libevent
     INFO("running libevent loop");
@@ -51,7 +51,7 @@
 
 error :
     if (ctx)
-        dbfs_release(ctx);
+        dbfs_free(ctx);
     
     if (signals)
         signals_free(signals);
--- a/src/dbfs.h	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs.h	Thu Oct 16 22:56:29 2008 +0300
@@ -15,11 +15,11 @@
 /*
  * Create the evsql and evfuse contexts and run the fs
  */
-struct dbfs *dbfs_open (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo);
+struct dbfs *dbfs_new (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo);
 
 /*
  * Release the dbfs's resources and free it
  */
-void dbfs_release (struct dbfs *ctx);
+void dbfs_free (struct dbfs *ctx);
 
 #endif /* DBFS_H */
--- a/src/dbfs/common.c	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/common.c	Thu Oct 16 22:56:29 2008 +0300
@@ -50,14 +50,15 @@
     int err = 0;
     
     uint16_t mode;
-    uint64_t size, nlink;
+    uint32_t size = 0;  // NULL for non-REG inodes
+    uint64_t nlink;
     const char *type;
     
     // extract the data
     if (0
         ||  evsql_result_string(res, row, col_offset + 0, &type,       0 ) // inodes.type
         ||  evsql_result_uint16(res, row, col_offset + 1, &mode,       0 ) // inodes.mode
-        ||  evsql_result_uint64(res, row, col_offset + 2, &size,       0 ) // inodes.size
+        ||  evsql_result_uint32(res, row, col_offset + 2, &size,       1 ) // size
         ||  evsql_result_uint64(res, row, col_offset + 3, &nlink,      0 ) // count(*)
     )
         EERROR(err = EIO, "invalid db data");
--- a/src/dbfs/core.c	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/core.c	Thu Oct 16 22:56:29 2008 +0300
@@ -57,10 +57,10 @@
     // query and params
     const char *sql = 
         "SELECT"
-        " inodes.ino, inodes.type, inodes.mode, inodes.size, count(*)"
+        " inodes.ino, inodes.type, inodes.mode, dbfs_lo_size(data), count(*)"
         " FROM file_tree INNER JOIN inodes ON (file_tree.inode = inodes.ino)"
         " WHERE file_tree.parent = $1::int4 AND file_tree.name = $2::varchar"
-        " GROUP BY inodes.ino, inodes.type, inodes.mode, inodes.size";
+        " GROUP BY inodes.ino, inodes.type, inodes.mode, data";
     
     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
         EVSQL_PARAM ( UINT32 ),
@@ -130,10 +130,10 @@
 
     const char *sql =
         "SELECT"
-        " inodes.type, inodes.mode, inodes.size, count(*)"
+        " inodes.type, inodes.mode, dbfs_lo_size(data), count(*)"
         " FROM inodes"
         " WHERE inodes.ino = $1::int4"
-        " GROUP BY inodes.type, inodes.mode, inodes.size";
+        " GROUP BY inodes.type, inodes.mode, data";
 
     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
         EVSQL_PARAM ( UINT32 ),
--- a/src/dbfs/dbfs.c	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/dbfs.c	Thu Oct 16 22:56:29 2008 +0300
@@ -4,7 +4,6 @@
 #include "dbfs.h"
 #include "../dbfs.h"
 #include "../lib/log.h"
-#include "../lib/misc.h"
 
 static struct fuse_lowlevel_ops dbfs_llops = {
 
@@ -15,6 +14,12 @@
 
     .getattr        = dbfs_getattr,
 
+    .open           = dbfs_open,
+    .read           = dbfs_read,
+    // .write       = dbfs_write,
+    .flush          = dbfs_flush,
+    .release        = dbfs_release,
+
     .opendir        = dbfs_opendir,
     .readdir        = dbfs_readdir,
     .releasedir     = dbfs_releasedir,
@@ -43,7 +48,7 @@
     event_base_loopbreak(ctx->ev_base);
 }
 
-struct dbfs *dbfs_open (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo) {
+struct dbfs *dbfs_new (struct event_base *ev_base, struct fuse_args *args, const char *db_conninfo) {
     struct dbfs *ctx = NULL;
 
     // alloc ctx
@@ -66,12 +71,12 @@
 
 error:
     if (ctx)
-        dbfs_release(ctx);
+        dbfs_free(ctx);
 
     return NULL;
 }    
 
-void dbfs_release (struct dbfs *ctx) {
+void dbfs_free (struct dbfs *ctx) {
     // cleanup
     if (ctx->ev_fuse) {
         evfuse_free(ctx->ev_fuse);
--- a/src/dbfs/dirop.c	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/dirop.c	Thu Oct 16 22:56:29 2008 +0300
@@ -228,12 +228,12 @@
  */
 void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
     struct dbfs *ctx = fuse_req_userdata(req);
-    struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh;
+    struct dbfs_dirop *dirop;
     int err;
 
     // get the op
     if ((dirop = (struct dbfs_dirop *) dbfs_op_req(req, ino, fi)) == NULL)
-        SERROR(err = EIO);
+        return;
     
     INFO("[dbfs.readdir %p:%p] ino=%lu, size=%zu, off=%zu, fi=%p : trans=%p", dirop, req, ino, size, off, fi, dirop->base.trans);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbfs/fileop.c	Thu Oct 16 22:56:29 2008 +0300
@@ -0,0 +1,245 @@
+#include <stdlib.h>
+#include <assert.h>
+
+#include <postgresql/libpq/libpq-fs.h>
+
+#include "dbfs.h"
+#include "op_base.h"
+#include "../lib/log.h"
+
+struct dbfs_fileop {
+    struct dbfs_op base;
+
+    uint32_t lo_fd;
+};
+
+static void _dbfs_fileop_free (struct dbfs_op *op_base) {
+    struct dbfs_fileop *fop = (struct dbfs_fileop *) op_base;
+    
+    /* no-op */
+    (void) fop;
+}
+
+static void dbfs_open_res (const struct evsql_result_info *res, void *arg) {
+    struct dbfs_fileop *fop = arg;
+    int err;
+
+    // check the results
+    if ((err = _dbfs_check_res(res, 1, 2)))
+        SERROR(err = (err ==  1 ? ENOENT : EIO));
+
+    const char *type;
+
+    // extract the data
+    if (0
+        ||  evsql_result_string(res, 0, 0, &type,           0 ) // inodes.type
+        ||  evsql_result_uint32(res, 0, 1, &fop->lo_fd,     0 ) // fd
+    )
+        SERROR(err = EIO);
+
+    // is it a dir?
+    if (_dbfs_mode(type) != S_IFREG)
+        EERROR(err = ENOENT, "wrong type: %s", type);
+    
+    INFO("[dbfs.open %p:%p] -> ino=%lu, type=%s", fop, fop->base.req, (unsigned long int) fop->base.ino, type);
+    
+    // open_fn done, do the open_reply
+    if ((err = dbfs_op_open_reply(&fop->base)))
+        goto error;
+
+    // success, fallthrough for evsql_result_free
+    err = 0;
+
+error:
+    if (err)
+        // fail it
+        dbfs_op_fail(&fop->base, err);
+    
+    // free
+    evsql_result_free(res);
+}
+
+static void dbfs_fileop_open (struct dbfs_op *op_base) {
+    struct dbfs_fileop *fop = (struct dbfs_fileop *) op_base;
+    struct dbfs *ctx = fuse_req_userdata(fop->base.req);
+    int err;
+    
+    // make sure the file actually exists
+    const char *sql =
+        "SELECT"
+        " inodes.type, lo_open(inodes.data, $1::int4) AS fd"
+        " FROM inodes"
+        " WHERE inodes.ino = $2::int4";
+
+    static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
+        EVSQL_PARAM ( UINT32 ),
+        EVSQL_PARAM ( UINT32 ),
+
+        EVSQL_PARAMS_END
+    };
+
+    // build params
+    if (0
+        ||  evsql_param_uint32(&params, 0, INV_READ | INV_WRITE)
+        ||  evsql_param_uint32(&params, 1, fop->base.ino)
+    )
+        SERROR(err = EIO);
+        
+    // query
+    if (evsql_query_params(ctx->db, fop->base.trans, sql, &params, dbfs_open_res, fop) == NULL)
+        SERROR(err = EIO);
+
+    // ok, wait for the info results
+    return;
+
+error:
+    // fail it
+    dbfs_op_fail(&fop->base, err);
+}
+
+void dbfs_open (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
+    struct dbfs *ctx = fuse_req_userdata(req);
+    struct dbfs_fileop *fop = NULL;
+    int err;
+    
+    // allocate it
+    if ((fop = calloc(1, sizeof(*fop))) == NULL && (err = EIO))
+        ERROR("calloc");
+
+    // do the op_open
+    if ((err = dbfs_op_open(ctx, &fop->base, req, ino, fi, _dbfs_fileop_free, dbfs_fileop_open)))
+        ERROR("dbfs_op_open");
+    
+    // log
+    INFO("[dbfs.open %p:%p] ino=%lu, fi->flags=%04X", fop, req, ino, fi->flags);
+    
+    // wait
+    return;
+
+error:
+    if (fop) {
+        // we can fail normally
+        dbfs_op_fail(&fop->base, err);
+
+    } else {
+        // must error out manually as we couldn't alloc the context
+        if ((err = fuse_reply_err(req, err)))
+            EWARNING(err, "fuse_reply_err");
+    }
+}
+
+void dbfs_read_res (const struct evsql_result_info *res, void *arg) {
+    struct dbfs_fileop *fop = arg;
+    int err;
+    const char *buf;
+    size_t size;
+ 
+    // check the results
+    if ((err = _dbfs_check_res(res, 1, 1)) < 0)
+        SERROR(err = EIO);
+        
+    // get the data
+    if (evsql_result_buf(res, 0, 0, &buf, &size, 0))
+        SERROR(err = EIO);
+
+    INFO("[dbfs.read %p:%p] -> size=%zu", fop, fop->base.req, size);
+        
+    // send it
+    if ((err = fuse_reply_buf(fop->base.req, buf, size)))
+        EERROR(err, "fuse_reply_buf");
+    
+    // ok, req handled
+    if ((err = dbfs_op_req_done(&fop->base)))
+        goto error;
+
+    // good, fallthrough
+    err = 0;
+
+error:
+    if (err)
+        dbfs_op_fail(&fop->base, err);
+
+    // free
+    evsql_result_free(res);
+}
+
+void dbfs_read (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
+    struct dbfs *ctx = fuse_req_userdata(req);
+    struct dbfs_fileop *fop;
+    int err;
+    
+    // get the op
+    if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL)
+        return;
+
+    // log
+    INFO("[dbfs.read %p:%p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", fop, req, ino, size, off, fi->flags);
+
+    // query
+    const char *sql = 
+        "SELECT"
+        " lo_pread($1::int4, $2::int4, $3::int4)";
+    
+    static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
+        EVSQL_PARAM ( UINT32 ), // fd
+        EVSQL_PARAM ( UINT32 ), // len
+        EVSQL_PARAM ( UINT32 ), // off
+
+        EVSQL_PARAMS_END
+    };
+
+    // build params
+    if (0
+        ||  evsql_param_uint32(&params, 0, fop->lo_fd)
+        ||  evsql_param_uint32(&params, 1, size)
+        ||  evsql_param_uint32(&params, 2, off)
+    )
+        SERROR(err = EIO);
+        
+    // query
+    if (evsql_query_params(ctx->db, fop->base.trans, sql, &params, dbfs_read_res, fop) == NULL)
+        SERROR(err = EIO);
+
+    // ok, wait for the info results
+    return;
+
+error:
+    // fail it
+    dbfs_op_fail(&fop->base, err);
+}
+
+void dbfs_write (struct fuse_req *req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) {
+
+}
+
+void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
+    struct dbfs_fileop *fop;
+    int err;
+
+    // get the fop
+    if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL)
+        return;
+    
+    // log
+    INFO("[dbfs.flush %p:%p] ino=%lu", fop, req, ino);
+    
+    // and reply...
+    if ((err = fuse_reply_err(req, 0)))
+        EWARNING(err, "fuse_reply_err");
+
+    // done
+    if ((err = dbfs_op_req_done(&fop->base)))
+        goto error;
+
+    // good
+    return;
+
+error:
+    dbfs_op_fail(&fop->base, err);
+}
+
+void dbfs_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
+    // just passthrough to dbfs_op
+    // the lo_fd will be closed automatically
+    dbfs_op_release(req, ino, fi);
+}
--- a/src/dbfs/op_base.h	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/op_base.h	Thu Oct 16 22:56:29 2008 +0300
@@ -73,6 +73,8 @@
  * Lookup the op for the given fi, validate params, and assign the new req.
  *
  * In case the op failed previously, this will error the req and return NULL, indicating that the req has been handled.
+ *
+ * Repeat, if this returns NULL, consider req invalid.
  */
 struct dbfs_op *dbfs_op_req (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
 
--- a/src/dbfs/ops.h	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/dbfs/ops.h	Thu Oct 16 22:56:29 2008 +0300
@@ -16,4 +16,10 @@
 void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi);
 void dbfs_releasedir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
 
+/* fileop.c */
+void dbfs_open (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
+void dbfs_read (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi);
+void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
+void dbfs_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi);
+
 #endif /* DBFS_OPS_H */
--- a/src/evsql.h	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/evsql.h	Thu Oct 16 22:56:29 2008 +0300
@@ -231,6 +231,7 @@
 
 // fetch the raw binary value from a result set, and return it via ptr
 // if size is nonzero, check that the size of the field data matches
+int evsql_result_buf    (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok);
 int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok);
 int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok);
 
--- a/src/evsql/util.c	Thu Oct 16 22:04:53 2008 +0300
+++ b/src/evsql/util.c	Thu Oct 16 22:56:29 2008 +0300
@@ -64,7 +64,7 @@
     }
 }
 
-int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) {
+int evsql_result_buf (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok) {
     *ptr = NULL;
 
     switch (res->evsql->type) {
@@ -79,10 +79,8 @@
             if (PQfformat(res->result.pq, col) != 1)
                 ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col));
     
-            if (size && PQgetlength(res->result.pq, row, col) != size)
-                ERROR("[%zu:%zu] field size mismatch: %zu -> %d", row, col, size, PQgetlength(res->result.pq, row, col));
-
-            *ptr = PQgetvalue(res->result.pq, row, col);
+            *size = PQgetlength(res->result.pq, row, col);
+            *ptr  = PQgetvalue(res->result.pq, row, col);
 
             return 0;
 
@@ -94,6 +92,21 @@
     return -1;
 }
 
+int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) {
+    size_t real_size;
+
+    if (evsql_result_buf(res, row, col, ptr, &real_size, nullok))
+        goto error;
+
+    if (size && real_size != size)
+        ERROR("[%zu:%zu] field size mismatch: %zu -> %zu", row, col, size, real_size);
+     
+    return 0;
+
+error:
+    return -1;
+}
+
 int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok) {
     return evsql_result_binary(res, row, col, ptr, 0, nullok);
 }