src/dbfs.c
changeset 26 61668c57f4bb
parent 25 99a41f48e29b
child 27 461be4cd34a3
equal deleted inserted replaced
25:99a41f48e29b 26:61668c57f4bb
     1 
     1 
     2 /*
     2 /*
     3  * A simple PostgreSQL-based filesystem.
     3  * A simple PostgreSQL-based filesystem.
     4  */
     4  */
     5 
     5 
       
     6 #include <stdlib.h>
     6 #include <string.h>
     7 #include <string.h>
     7 #include <errno.h>
     8 #include <errno.h>
       
     9 #include <assert.h>
     8 
    10 
     9 #include <event2/event.h>
    11 #include <event2/event.h>
    10 
    12 
    11 #include "evfuse.h"
    13 #include "evfuse.h"
    12 #include "evsql.h"
    14 #include "evsql.h"
   274 error:
   276 error:
   275     if ((err = fuse_reply_err(req, err)))
   277     if ((err = fuse_reply_err(req, err)))
   276         EWARNING(err, "fuse_reply_err");
   278         EWARNING(err, "fuse_reply_err");
   277 }
   279 }
   278 
   280 
       
   281 struct dbfs_dirop {
       
   282     struct fuse_file_info *fi;
       
   283     struct fuse_req *req;
       
   284 
       
   285     struct evsql_trans *trans;
       
   286     
       
   287     // opendir has returned and releasedir hasn't been called yet
       
   288     int open;
       
   289 };
       
   290 
       
   291 /*
       
   292  * Free the dirop, aborting any in-progress transaction.
       
   293  *
       
   294  * req must be NULL.
       
   295  */
       
   296 static void dbfs_dirop_free (struct dbfs_dirop *dirop) {
       
   297     assert(dirop->req == NULL);
       
   298 
       
   299     if (dirop->trans)
       
   300         evsql_trans_abort(dirop->trans);
       
   301 
       
   302     free(dirop);
       
   303 }
       
   304 
       
   305 /*
       
   306  * The opendir transaction is ready
       
   307  */
       
   308 static void dbfs_dirop_ready (struct evsql_trans *trans, void *arg) {
       
   309     struct dbfs_dirop *dirop = arg;
       
   310     struct fuse_req *req = dirop->req; dirop->req = NULL;
       
   311     int err;
       
   312 
       
   313     INFO("[dbfs.openddir %p:%p] -> trans=%p", dirop, req, trans);
       
   314 
       
   315     // remember the transaction
       
   316     dirop->trans = trans;
       
   317 
       
   318     // send the openddir reply
       
   319     if ((err = fuse_reply_open(dirop->req, dirop->fi)))
       
   320         EERROR(err, "fuse_reply_open");
       
   321     
       
   322     // dirop is now open
       
   323     dirop->open = 1;
       
   324 
       
   325     // ok, wait for the next fs req
       
   326     return;
       
   327 
       
   328 error:
       
   329     dbfs_dirop_free(dirop);
       
   330 
       
   331     if ((err = fuse_reply_err(req, err)))
       
   332         EWARNING(err, "fuse_reply_err");
       
   333 }
       
   334 
       
   335 static void dbfs_dirop_done (struct evsql_trans *trans, void *arg) {
       
   336     struct dbfs_dirop *dirop = arg;
       
   337     int err;
       
   338     
       
   339 
       
   340 }
       
   341 
       
   342 static void dbfs_dirop_error (struct evsql_trans *trans, void *arg) {
       
   343     struct dbfs_dirop *dirop = arg;
       
   344     int err;
       
   345 
       
   346     INFO("[dbfs:dirop %p:%p] evsql transaction error: %s", dirop, dirop->req, evsql_trans_error(trans));
       
   347     
       
   348     // deassociate the trans
       
   349     dirop->trans = NULL;
       
   350     
       
   351     // error out and pending req
       
   352     if (dirop->req) {
       
   353         if ((err = fuse_reply_err(dirop->req, EIO)))
       
   354             EWARNING(err, "fuse_erply_err");
       
   355 
       
   356         dirop->req = NULL;
       
   357 
       
   358         // only free the dirop if it isn't open
       
   359         if (!dirop->open)
       
   360             dbfs_dirop_free(dirop);
       
   361     }
       
   362 }
       
   363 
       
   364 static void dbfs_opendir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
       
   365     struct dbfs *ctx = fuse_req_userdata(req);
       
   366     struct dbfs_dirop *dirop = NULL;
       
   367     int err;
       
   368     
       
   369     // allocate it
       
   370     if ((dirop = calloc(1, sizeof(*dirop))) == NULL && (err = EIO))
       
   371         ERROR("calloc");
       
   372 
       
   373     INFO("[dbfs.opendir %p:%p] ino=%lu, fi=%p", dirop, req, ino, fi);
       
   374         
       
   375     // store the dirop
       
   376     fi->fh = (uint64_t) dirop;
       
   377     dirop->req = req;
       
   378     dirop->fi = fi;
       
   379 
       
   380     // start a new transaction
       
   381     if (evsql_trans(ctx->db, EVSQL_TRANS_SERIALIZABLE, dbfs_dirop_error, dbfs_dirop_ready, dbfs_dirop_done, dirop))
       
   382         SERROR(err = EIO);
       
   383     
       
   384     // XXX: handle interrupts
       
   385     
       
   386     // wait
       
   387     return;
       
   388 
       
   389 error:
       
   390     // we handle the req
       
   391     dirop->req = NULL;
       
   392 
       
   393     dbfs_dirop_free(dirop);
       
   394 
       
   395     if ((err = fuse_reply_err(req, err)))
       
   396         EWARNING(err, "fuse_reply_err");
       
   397 }
       
   398 
       
   399 static void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
       
   400     struct dbfs *ctx = fuse_req_userdata(req);
       
   401     struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh;
       
   402     int err;
       
   403 
       
   404     INFO("[dbfs.readdir %p:%p] ino=%lu, size=%zu, off=%zu, fi=%p : trans=%p", dirop, req, ino, size, off, fi, dirop->trans);
       
   405 
       
   406     // update dirop
       
   407     dirop->req = req;
       
   408     assert(dirop->fi == fi);
       
   409 
       
   410     // select all relevant file entries
       
   411     const char *sql = 
       
   412         "SELECT"
       
   413         " \"file_tree.offset\", file_tree.name, inodes.ino, inodes.type"
       
   414         " FROM file_tree LEFT OUTER JOIN inodes ON (file_tree.inode = inodes.ino)"
       
   415         " WHERE file_tree.parent = $1::int4 AND \"file_tree.offset\" >= $2::int4"
       
   416         " LIMIT $3::int4";
       
   417 
       
   418     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
       
   419         EVSQL_PARAM ( UINT32 ),
       
   420         EVSQL_PARAM ( UINT32 ),
       
   421         EVSQL_PARAM ( UINT32 ),
       
   422 
       
   423         EVSQL_PARAMS_END
       
   424     };
       
   425 
       
   426     // XXX: incomplete
       
   427 }
       
   428 
       
   429 static void dbfs_releasedir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
       
   430     struct dbfs *ctx = fuse_req_userdata(req);
       
   431     struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh;
       
   432     int err;
       
   433 
       
   434     (void) ctx;
       
   435 
       
   436     INFO("[dbfs.releasedir %p:%p] ino=%lu, fi=%p : trans=%p", dirop, req, ino, fi, dirop->trans);
       
   437 
       
   438     // update dirop. Must keep it open so that dbfs_dirop_error won't free it
       
   439     dirop->req = req;
       
   440     assert(dirop->fi == fi);
       
   441 
       
   442     // we can commit the transaction, although we didn't make any changes
       
   443     // if this fails the transaction, then dbfs_dirop_error will take care of sending the error, and dirop->req will be
       
   444     // NULL
       
   445     if (evsql_trans_commit(dirop->trans))
       
   446         SERROR(err = EIO);
       
   447 
       
   448     // not open anymore
       
   449     dirop->open = 0;
       
   450 
       
   451     // XXX: handle interrupts
       
   452     
       
   453     // wait
       
   454     return;
       
   455 
       
   456 error:
       
   457     if (dirop->req) {
       
   458         // we handle the req
       
   459         dirop->req = NULL;
       
   460 
       
   461         dbfs_dirop_free(dirop);
       
   462 
       
   463         if ((err = fuse_reply_err(req, err)))
       
   464             EWARNING(err, "fuse_reply_err");
       
   465     }
       
   466 }
       
   467 
   279 struct fuse_lowlevel_ops dbfs_llops = {
   468 struct fuse_lowlevel_ops dbfs_llops = {
   280 
   469 
   281     .init           = dbfs_init,
   470     .init           = dbfs_init,
   282     .destroy        = dbfs_destroy,
   471     .destroy        = dbfs_destroy,
   283     
   472     
   284     .lookup         = dbfs_lookup,
   473     .lookup         = dbfs_lookup,
   285 
   474 
   286     .getattr        = dbfs_getattr,
   475     .getattr        = dbfs_getattr,
       
   476 
       
   477     .opendir        = dbfs_opendir,
       
   478     .releasedir     = dbfs_releasedir,
   287 };
   479 };
   288 
   480 
   289 void dbfs_sql_error (struct evsql *evsql, void *arg) {
   481 void dbfs_sql_error (struct evsql *evsql, void *arg) {
   290     struct dbfs *ctx = arg;
   482     struct dbfs *ctx = arg;
   291 
   483