# HG changeset patch # User Tero Marttila # Date 1224698837 -10800 # Node ID 03017f5f0087318aa91d9194cc2aba70424313a2 # Parent 7e655be2189a12f617262e775f18ef3f7e895458 add MODE param to makefile, fix INFO_DISABLED, add some constraints to the .sql, fix some -err's, EVSQL_PQ_ARBITRARY_TYPE_OID, and make read/write transactionless diff -r 7e655be2189a -r 03017f5f0087 Makefile --- a/Makefile Wed Oct 22 18:17:08 2008 +0300 +++ b/Makefile Wed Oct 22 21:07:17 2008 +0300 @@ -5,15 +5,24 @@ INCLUDE_PATHS = -I${LIBEVENT_PATH}/include -I${LIBFUSE_PATH}/include LDLIBS = -levent -lfuse -lpq -ifdef DEBUG -DEBUG_FLAGS = -DDEBUG_ENABLED -else -DEBUG_FLAGS = +# default is TEST +ifndef MODE +MODE = TEST +endif + +ifeq ($(MODE), DEBUG) +MODE_CFLAGS = -g -DDEBUG_ENABLED +else ifeq ($(MODE), DEV) +MODE_CFLAGS = -g +else ifeq ($(MODE), TEST) +MODE_CFLAGS = -g -DINFO_DISABLED +else ifeq ($(MODE), RELEASE) +MODE_CFLAGS = -DINFO_DISABLED -O2 endif # XXX: ugh... use `pkg-config fuse` -DEFINES = -D_FILE_OFFSET_BITS=64 ${DEBUG_FLAGS} -MY_CFLAGS = -Wall -g -std=gnu99 +DEFINES = -D_FILE_OFFSET_BITS=64 +MY_CFLAGS = -Wall -std=gnu99 $(MODE_CFLAGS) BIN_NAMES = helloworld hello simple_hello evpq_test url_test dbfs BIN_PATHS = $(addprefix bin/,$(BIN_NAMES)) diff -r 7e655be2189a -r 03017f5f0087 doc/fuse_db.sql --- a/doc/fuse_db.sql Wed Oct 22 18:17:08 2008 +0300 +++ b/doc/fuse_db.sql Wed Oct 22 21:07:17 2008 +0300 @@ -5,24 +5,35 @@ CREATE SEQUENCE ino_seq START 64; +-- inodes CREATE TABLE inodes ( ino int4 primary key DEFAULT nextval('ino_seq'::regclass), type char(3) NOT NULL, mode int2 NOT NULL, data oid, - link_path varchar(512) + link_path varchar(512), + + -- sanity checks + CONSTRAINT inodes_valid_reg CHECK (data IS NULL OR type = 'REG'), + CONSTRAINT inodes_valid_lnk CHECK (link_path IS NULL OR type = 'LNK') ); +-- filesystem layout CREATE TABLE file_tree ( "offset" serial4 primary key, name varchar(256), ino int4 references inodes(ino) NOT NULL, ino_dir int4 references inodes(ino), parent int4, - + + -- structure CONSTRAINT file_tree_uniq_direntry UNIQUE (parent, name), CONSTRAINT file_tree_uniq_dir_ino UNIQUE (ino_dir), - CONSTRAINT file_tree_exist_parent FOREIGN KEY (parent) REFERENCES file_tree(ino_dir) + CONSTRAINT file_tree_exist_parent FOREIGN KEY (parent) REFERENCES file_tree(ino_dir), + + -- sanity checks + CONSTRAINT file_tree_valid_root CHECK ((parent IS NULL AND name IS NULL AND ino = 1) OR (name IS NOT NULL and parent IS NOT NULL AND ino != 1)), + CONSTRAINT file_tree_valid_dir CHECK (ino_dir IS NULL OR ino_dir = ino) ); INSERT INTO inodes (ino, type, mode, data) VALUES @@ -33,11 +44,12 @@ (NULL, NULL, 1, 1 ), ('foo', 1, 2, NULL ); +-- not sure how these work, I guess statements in functions aren't their own transactions +CREATE OR REPLACE FUNCTION lo_pread_oid (IN obj oid, IN len int4, IN "off" int4) RETURNS bytea LANGUAGE SQL STRICT AS 'select lo_open($1, 393216); select lo_lseek(0, $3, 0); select loread(0, $2);'; +CREATE OR REPLACE FUNCTION lo_pwrite_oid (IN obj oid, IN buf bytea, IN "off" int4) RETURNS int4 LANGUAGE SQL STRICT AS 'select lo_open($1, 393216); select lo_lseek(0, $3, 0); select lowrite(0, $2);'; + +CREATE OR REPLACE FUNCTION lo_otruncate (IN obj oid, IN len int4) RETURNS oid LANGUAGE SQL STRICT AS 'select lo_truncate(lo_open($1, 393216), $2); select $1;'; CREATE OR REPLACE FUNCTION lo_size (oid) RETURNS int4 LANGUAGE SQL STABLE RETURNS NULL ON NULL INPUT AS 'select lo_lseek(lo_open($1, 262144), 0, 2);'; -CREATE OR REPLACE FUNCTION lo_pread (IN fd int4, IN len int4, IN "off" int4) RETURNS bytea LANGUAGE SQL STRICT AS 'select lo_lseek($1, $3, 0); select loread($1, $2);'; -CREATE OR REPLACE FUNCTION lo_pwrite (IN fd int4, IN buf bytea, IN "off" int4) RETURNS int4 LANGUAGE SQL STRICT AS 'select lo_lseek($1, $3, 0); select lowrite($1, $2);'; -CREATE OR REPLACE FUNCTION lo_otruncate (IN oid, IN len int4) RETURNS oid LANGUAGE SQL STRICT AS 'select lo_truncate(lo_open($1, 393216), $2); select $1;'; - CREATE OR REPLACE FUNCTION dbfs_size (type char, oid, link varchar) RETURNS int4 LANGUAGE SQL STABLE AS $$ SELECT CASE $1 WHEN 'LNK' THEN char_length($3) diff -r 7e655be2189a -r 03017f5f0087 src/dbfs/fileop.c --- a/src/dbfs/fileop.c Wed Oct 22 18:17:08 2008 +0300 +++ b/src/dbfs/fileop.c Wed Oct 22 21:07:17 2008 +0300 @@ -7,10 +7,17 @@ #include "op_base.h" #include "../lib/log.h" +/* + * A file-operation, i.e. a sequence consisting of an OPEN, a multitude of READ/WRITE, followed by zero or more FLUSHes, and finally a single RELEASE. + * + * For historical reasons this opens a transaction and keeps it between open/release, but reads/writes now use the oid directly and are transactionless. + */ + struct dbfs_fileop { struct dbfs_op base; - - uint32_t lo_fd; + + uint32_t oid; +// uint32_t lo_fd; }; static void _dbfs_fileop_free (struct dbfs_op *op_base) { @@ -33,7 +40,7 @@ // 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 + || evsql_result_uint32(res, 0, 1, &fop->oid, 0 ) // inodes.data ) SERROR(err = EIO); @@ -67,21 +74,19 @@ // make sure the file actually exists const char *sql = "SELECT" - " inodes.type, lo_open(inodes.data, $1::int4) AS fd" + " inodes.type, inodes.data" " FROM inodes" - " WHERE inodes.ino = $2::int4"; + " WHERE inodes.ino = $1::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(¶ms, 0, INV_READ | INV_WRITE) - || evsql_param_uint32(¶ms, 1, fop->base.ino) + || evsql_param_uint32(¶ms, 0, fop->base.ino) ) SERROR(err = EIO); @@ -123,13 +128,13 @@ } else { // must error out manually as we couldn't alloc the context - if ((err = fuse_reply_err(req, err))) + 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; + struct fuse_req *req = arg; int err; const char *buf; size_t size; @@ -142,22 +147,19 @@ if (evsql_result_binary(res, 0, 0, &buf, &size, 0)) SERROR(err = EIO); - INFO("\t[dbfs.read %p:%p] -> size=%zu", fop, fop->base.req, size); + INFO("\t[dbfs.read %p] -> size=%zu", req, size); // send it - if ((err = fuse_reply_buf(fop->base.req, buf, size))) + if ((err = -fuse_reply_buf(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); + fuse_reply_err(req, err); + // free evsql_result_free(res); @@ -165,51 +167,47 @@ 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); + INFO("[dbfs.read %p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", req, ino, size, off, fi->flags); // query const char *sql = "SELECT" - " lo_pread($1::int4, $2::int4, $3::int4)"; + " lo_pread_oid(data, $1::int4, $2::int4)" + " FROM inodes" + " WHERE ino = $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_PARAM ( UINT32 ), // ino EVSQL_PARAMS_END }; // build params if (0 - || evsql_param_uint32(¶ms, 0, fop->lo_fd) - || evsql_param_uint32(¶ms, 1, size) - || evsql_param_uint32(¶ms, 2, off) + || evsql_param_uint32(¶ms, 0, size) + || evsql_param_uint32(¶ms, 1, off) + || evsql_param_uint32(¶ms, 2, ino) ) SERROR(err = EIO); - // query - if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_read_res, fop) == NULL) + // query, transactionless + if (evsql_query_params(ctx->db, NULL, sql, ¶ms, dbfs_read_res, req) == NULL) SERROR(err = EIO); // ok, wait for the info results return; error: - // fail it - dbfs_op_fail(&fop->base, err); + fuse_reply_err(req, err); } void dbfs_write_res (const struct evsql_result_info *res, void *arg) { - struct dbfs_fileop *fop = arg; + struct fuse_req *req = arg; int err; uint32_t size; @@ -221,22 +219,18 @@ if (evsql_result_uint32(res, 0, 0, &size, 0)) SERROR(err = EIO); - INFO("\t[dbfs.write %p:%p] -> size=%lu", fop, fop->base.req, (long unsigned int) size); + INFO("\t[dbfs.write %p] -> size=%lu", req, (long unsigned int) size); // send it - if ((err = fuse_reply_write(fop->base.req, size))) + if ((err = -fuse_reply_write(req, size))) EERROR(err, "fuse_reply_write"); - - // 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); + fuse_reply_err(req, err); // free evsql_result_free(res); @@ -244,47 +238,43 @@ 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) { 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.write %p:%p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", fop, req, ino, size, off, fi->flags); + INFO("[dbfs.write %p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", req, ino, size, off, fi->flags); // query const char *sql = "SELECT" - " lo_pwrite($1::int4, $2::bytea, $3::int4)"; + " lo_pwrite_oid(data, $1::bytea, $2::int4)" + " FROM inodes" + " WHERE ino = $3::int4"; static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { - EVSQL_PARAM ( UINT32 ), // fd EVSQL_PARAM ( BINARY ), // buf EVSQL_PARAM ( UINT32 ), // off + EVSQL_PARAM ( UINT32 ), // oid EVSQL_PARAMS_END }; // build params if (0 - || evsql_param_uint32(¶ms, 0, fop->lo_fd) - || evsql_param_binary(¶ms, 1, buf, size) - || evsql_param_uint32(¶ms, 2, off) + || evsql_param_binary(¶ms, 0, buf, size) + || evsql_param_uint32(¶ms, 1, off) + || evsql_param_uint32(¶ms, 2, ino) ) SERROR(err = EIO); // query - if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_write_res, fop) == NULL) + if (evsql_query_params(ctx->db, NULL, sql, ¶ms, dbfs_write_res, req) == NULL) SERROR(err = EIO); // ok, wait for the info results return; error: - // fail it - dbfs_op_fail(&fop->base, err); + fuse_reply_err(req, err); } void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { @@ -299,7 +289,7 @@ INFO("[dbfs.flush %p:%p] ino=%lu", fop, req, ino); // and reply... - if ((err = fuse_reply_err(req, 0))) + if ((err = -fuse_reply_err(req, 0))) EWARNING(err, "fuse_reply_err"); // done diff -r 7e655be2189a -r 03017f5f0087 src/dbfs/link.c --- a/src/dbfs/link.c Wed Oct 22 18:17:08 2008 +0300 +++ b/src/dbfs/link.c Wed Oct 22 21:07:17 2008 +0300 @@ -39,11 +39,11 @@ e.entry_timeout = CACHE_TIMEOUT; // reply - if ((err = fuse_reply_entry(req, &e))) + if ((err = -fuse_reply_entry(req, &e))) EERROR(err, "fuse_reply_entry"); error: - if (err && (err = fuse_reply_err(req, err))) + if (err && (err = -fuse_reply_err(req, err))) EWARNING(err, "fuse_reply_err"); // free @@ -87,7 +87,7 @@ return; error: - if ((err = fuse_reply_err(req, err))) + if ((err = -fuse_reply_err(req, err))) EWARNING(err, "fuse_reply_err"); } @@ -117,11 +117,11 @@ INFO("\t[dbfs.readlink %p] -> ino=%lu, type=%s, link=%s", req, (unsigned long int) ino, type, link); // reply - if ((err = fuse_reply_readlink(req, link))) + if ((err = -fuse_reply_readlink(req, link))) EERROR(err, "fuse_reply_readlink"); error: - if (err && (err = fuse_reply_err(req, err))) + if (err && (err = -fuse_reply_err(req, err))) EWARNING(err, "fuse_reply_err"); // free @@ -162,7 +162,7 @@ return; error: - if ((err = fuse_reply_err(req, err))) + if ((err = -fuse_reply_err(req, err))) EWARNING(err, "fuse_reply_err"); } @@ -181,11 +181,11 @@ INFO("\t[dbfs.unlink %p] -> OK", req); // reply - if ((err = fuse_reply_err(req, 0))) - EERROR(err, "fuse_reply_readlink"); + if ((err = -fuse_reply_err(req, 0))) + EERROR(err, "fuse_reply_err"); error: - if (err && (err = fuse_reply_err(req, err))) + if (err && (err = -fuse_reply_err(req, err))) EWARNING(err, "fuse_reply_err"); // free @@ -227,7 +227,7 @@ return; error: - if ((err = fuse_reply_err(req, err))) + if ((err = -fuse_reply_err(req, err))) EWARNING(err, "fuse_reply_err"); } @@ -266,6 +266,6 @@ return; error: - if ((err = fuse_reply_err(req, err))) + if ((err = -fuse_reply_err(req, err))) EWARNING(err, "fuse_reply_err"); } diff -r 7e655be2189a -r 03017f5f0087 src/dbfs/op_base.c --- a/src/dbfs/op_base.c Wed Oct 22 18:17:08 2008 +0300 +++ b/src/dbfs/op_base.c Wed Oct 22 21:07:17 2008 +0300 @@ -192,12 +192,26 @@ // validate assert(op); - assert(!op->req); assert(op->open); assert(op->ino == ino); + + // detect concurrent requests + if (op->req) { + // must handle req ourself, shouldn't fail the other req + WARNING("op.%p: concurrent req: %p -> %p", op, op->req, req); + + // XXX: ignore error errors... + fuse_reply_err(req, EBUSY); - // store the new req - op->req = req; + return NULL; + + } else + // store the new req + op->req = req; + + // inodes change? + if (op->ino != ino) + XERROR(err = EBADF, "op.%p: wrong ino: %u -> %lu", op, op->ino, ino); // detect earlier failures if (!op->trans && (err = EIO)) diff -r 7e655be2189a -r 03017f5f0087 src/dirbuf.c --- a/src/dirbuf.c Wed Oct 22 18:17:08 2008 +0300 +++ b/src/dirbuf.c Wed Oct 22 21:07:17 2008 +0300 @@ -70,7 +70,7 @@ int err; // send the reply, return the error later - err = fuse_reply_buf(req, buf->buf, buf->off); + err = -fuse_reply_buf(req, buf->buf, buf->off); DEBUG("\tdirbuf.done: size=%zu/%zu, err=%d", buf->off, buf->len, err); diff -r 7e655be2189a -r 03017f5f0087 src/evsql/evsql.c --- a/src/evsql/evsql.c Wed Oct 22 18:17:08 2008 +0300 +++ b/src/evsql/evsql.c Wed Oct 22 21:07:17 2008 +0300 @@ -864,7 +864,7 @@ // transform for (param = params->list, idx = 0; param->type; param++, idx++) { // `set for NULLs, otherwise not - query->params.types[idx] = param->data_raw ? 0 : 16; + query->params.types[idx] = param->data_raw ? 0 : EVSQL_PQ_ARBITRARY_TYPE_OID; // values query->params.values[idx] = param->data_raw; diff -r 7e655be2189a -r 03017f5f0087 src/evsql/evsql.h --- a/src/evsql/evsql.h Wed Oct 22 18:17:08 2008 +0300 +++ b/src/evsql/evsql.h Wed Oct 22 21:07:17 2008 +0300 @@ -133,4 +133,8 @@ // maximum length for a 'BEGIN TRANSACTION ...' query #define EVSQL_QUERY_BEGIN_BUF 512 +// the should the OID of some valid psql type... *ANY* valid psql type, doesn't matter, only used for NULLs +// 16 = bool in 8.3 +#define EVSQL_PQ_ARBITRARY_TYPE_OID 16 + #endif /* EVSQL_INTERNAL_H */ diff -r 7e655be2189a -r 03017f5f0087 src/lib/log.h --- a/src/lib/log.h Wed Oct 22 18:17:08 2008 +0300 +++ b/src/lib/log.h Wed Oct 22 21:07:17 2008 +0300 @@ -88,7 +88,8 @@ #define INFO(...) info(__VA_ARGS__) #define INFON(...) info_nonl(__VA_ARGS__) #else -#define INFO(...) (void) (__VA_ARGS__) +#define INFO(...) debug_dummy(0, __VA_ARGS__) +#define INFON(...) debug_dummy(0, __VA_ARGS__) #endif #endif /* LIB_LOG_H */