Thu, 03 Feb 2022 17:26:08 +0100
minimal working send_file with postgresql vfs
--- a/doc/development/postgresql_vfs.sql Tue Feb 01 20:07:42 2022 +0100 +++ b/doc/development/postgresql_vfs.sql Thu Feb 03 17:26:08 2022 +0100 @@ -8,6 +8,8 @@ lastmodified timestamp not null default current_date, creationdate timestamp not null default current_date, contentlength bigint not null default 0, + + resoid oid, unique(parent_id, nodename) );
--- a/doc/development/postgresql_vfs_testdata.sql Tue Feb 01 20:07:42 2022 +0100 +++ b/doc/development/postgresql_vfs_testdata.sql Thu Feb 03 17:26:08 2022 +0100 @@ -6,11 +6,11 @@ insert into Resource (nodename, iscollection) values ('', true); res_id := lastval(); - insert into Resource(parent_id, nodename) values - (res_id, 'file1.txt'), - (res_id, 'file2.txt'), - (res_id, 'file3.txt'), - (res_id, 'file4.txt'); + insert into Resource(parent_id, nodename, resoid) values + (res_id, 'file1.txt', (select lo_create(0))), + (res_id, 'file2.txt', (select lo_create(0))), + (res_id, 'file3.txt', (select lo_create(0))), + (res_id, 'file4.txt', (select lo_create(0))); insert into Resource(parent_id, nodename, iscollection) values (res_id, 'dir1', true); @@ -20,10 +20,10 @@ (res_id, 'dir2', true); res_id := lastval(); - insert into Resource(parent_id, nodename) values - (res_id, 'd1file1.txt'), - (res_id, 'd2file1.txt'), - (res_id, 'd2file2.txt'); + insert into Resource(parent_id, nodename, resoid) values + (res_id, 'd1file1.txt', (select lo_create(0))), + (res_id, 'd2file1.txt', (select lo_create(0))), + (res_id, 'd2file2.txt', (select lo_create(0))); end $$;
--- a/src/server/daemon/resourcepool.c Tue Feb 01 20:07:42 2022 +0100 +++ b/src/server/daemon/resourcepool.c Thu Feb 03 17:26:08 2022 +0100 @@ -145,6 +145,7 @@ if(resource) { resource->data.data = respool->type->getresourcedata(resourceData); resource->data.resourcepool = respool; + resource->resdata = resourceData; } else { respool->type->freeresource(respool->data, resourceData); log_ereport(LOG_CATASTROPHE, "resourcepool_lookup: OOM"); @@ -176,6 +177,10 @@ } else { err = 1; } + + if(respool->type->prepare(respool->data, resource->resdata)) { + err = -1; + } } if(err) { @@ -188,14 +193,17 @@ pthread_mutex_unlock(&respool->lock); - - return &resource->data; + return (ResourceData*)resource; } void resourcepool_free(Session *sn, Request *rq, ResourceData *resource) { ResourceDataPrivate *res = (ResourceDataPrivate*)resource; ResourcePool *respool = resource->resourcepool; + if(respool->type->finish(respool->data, res->resdata)) { + log_ereport(LOG_FAILURE, "resourcepool_free: finish failed"); + } + pthread_mutex_lock(&respool->lock); if(respool->numresources >= respool->resalloc) {
--- a/src/server/plugins/postgresql/resource.c Tue Feb 01 20:07:42 2022 +0100 +++ b/src/server/plugins/postgresql/resource.c Thu Feb 03 17:26:08 2022 +0100 @@ -118,10 +118,14 @@ } int pg_resourcepool_prepare(PgResourcePool *pg, PgResource *res) { + PGresult *result = PQexec(res->connection, "BEGIN"); + PQclear(result); // TODO: handle error return 0; } int pg_resourcepool_finish(PgResourcePool *pg, PgResource *res) { + PGresult *result = PQexec(res->connection, "COMMIT"); + PQclear(result); // TODO: handle error return 0; }
--- a/src/server/plugins/postgresql/vfs.c Tue Feb 01 20:07:42 2022 +0100 +++ b/src/server/plugins/postgresql/vfs.c Thu Feb 03 17:26:08 2022 +0100 @@ -72,6 +72,7 @@ resource_id,\n\ parent_id,\n\ '' as fullpath,\n\ + resoid,\n\ iscollection,\n\ lastmodified,\n\ creationdate,\n\ @@ -85,6 +86,7 @@ r.resource_id,\n\ r.parent_id,\n\ p.fullpath || '/' || r.nodename,\n\ + r.resoid,\n\ r.iscollection,\n\ r.lastmodified,\n\ r.creationdate,\n\ @@ -95,12 +97,12 @@ inner join resolvepath p on r.parent_id = p.resource_id\n\ where p.pathelm[p.pathdepth+1] = r.nodename\n\ )\n\ - select resource_id, parent_id, fullpath, iscollection from resolvepath\n\ + select resource_id, parent_id, fullpath, resoid, iscollection, lastmodified, creationdate, contentlength from resolvepath\n\ where fullpath = $1 ;"; // Same as sql_resolve_path, but it returns the root collection // params: $1: path string (should be '/') -static const char *sql_get_root = "select resource_id, parent_id, $1 as fullpath, true as iscollection, lastmodified, creationdate, contentlength from Resource where parent_id is null;"; +static const char *sql_get_root = "select resource_id, parent_id, $1 as fullpath, resoid, true as iscollection, lastmodified, creationdate, contentlength from Resource where parent_id is null;"; // Get all children of a specific collection // params: $1: parent resource_id @@ -155,6 +157,7 @@ const char *path, int64_t *parent_id, int64_t *resource_id, + Oid *oid, const char **resource_name, WSBool *iscollection, struct stat *s) @@ -191,7 +194,7 @@ NULL, NULL, 0); // 0: result in text format - + if(pathf) { free(pathf); } @@ -204,10 +207,10 @@ if(nrows == 1) { char *resource_id_str = PQgetvalue(result, 0, 0); char *parent_id_str = PQgetvalue(result, 0, 1); - char *iscol = PQgetvalue(result, 0, 3); - char *lastmodified = PQgetvalue(result, 0, 4); - char *creationdate = PQgetvalue(result, 0, 5); - char *contentlength = PQgetvalue(result, 0, 6); + char *iscol = PQgetvalue(result, 0, 4); + char *lastmodified = PQgetvalue(result, 0, 5); + char *creationdate = PQgetvalue(result, 0, 6); + char *contentlength = PQgetvalue(result, 0, 7); if(resource_id_str && parent_id_str) { if(util_strtoint(resource_id_str, resource_id)) { ret = 0; // success @@ -216,6 +219,14 @@ util_strtoint(parent_id_str, parent_id); } + if(oid) { + char *resoid = PQgetvalue(result, 0, 3); + int64_t roid; + if(resoid && util_strtoint(resoid, &roid)) { + *oid = roid; + } + } + if(iscollection && iscol) { *iscollection = iscol[0] == 't' ? TRUE : FALSE; } @@ -248,6 +259,9 @@ } } // TODO: lastmodified, creationdate + // set some test values != 0 + s->st_mtime = time(NULL); + if(contentlength) { int64_t len; if(util_strtoint(contentlength, &len)) { @@ -259,13 +273,17 @@ /* -------------------------- VFS functions -------------------------- */ SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) { + VFS *vfs = ctx->vfs; + PgVFS *pg = vfs->instance; + const char *resname; int64_t resource_id, parent_id; resource_id = -1; parent_id = -1; WSBool iscollection; struct stat s; - if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection, &s)) { + Oid oid = 0; + if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &oid, &resname, &iscollection, &s)) { return NULL; } @@ -279,9 +297,21 @@ return NULL; } + int fd = -1; + if(!iscollection) { + if (PQstatus(pg->connection) != CONNECTION_OK) { + fd = -2; + } + + int lo_mode = INV_READ; // TODO: evaluate oflags + fd = lo_open(pg->connection, oid, lo_mode); + } + pgfile->iscollection = iscollection; pgfile->resource_id = resource_id; pgfile->parent_id = parent_id; + pgfile->oid = oid; + pgfile->fd = fd; pgfile->s = s; file->ctx = ctx; @@ -296,7 +326,7 @@ int64_t parent_id, resource_id; const char *resname; WSBool iscollection; - return pg_resolve_path(ctx, path, &parent_id, &resource_id, &resname, &iscollection, buf); + return pg_resolve_path(ctx, path, &parent_id, &resource_id, NULL, &resname, &iscollection, buf); } int pg_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { @@ -359,22 +389,32 @@ /* -------------------------- VFS_IO functions -------------------------- */ ssize_t pg_vfs_io_read(SYS_FILE fd, void *buf, size_t nbyte) { - return 0; + PgVFS *pgvfs = fd->ctx->vfs->instance; + PgFile *pg = fd->data; + return lo_read(pgvfs->connection, pg->fd, buf, nbyte); } ssize_t pg_vfs_io_write(SYS_FILE fd, const void *buf, size_t nbyte) { + PgVFS *pgvfs = fd->ctx->vfs->instance; + return 0; } ssize_t pg_vfs_io_pread(SYS_FILE fd, void *buf, size_t nbyte, off_t offset) { + PgVFS *pgvfs = fd->ctx->vfs->instance; + return 0; } ssize_t pg_vfs_io_pwrite(SYS_FILE fd, const void *buf, size_t nbyte, off_t offset) { + PgVFS *pgvfs = fd->ctx->vfs->instance; + return 0; } off_t pg_vfs_io_seek(SYS_FILE fd, off_t offset, int whence) { + PgVFS *pgvfs = fd->ctx->vfs->instance; + return 0; } @@ -382,6 +422,11 @@ pool_handle_t *pool = fd->ctx->pool; PgFile *pg = fd->data; + if(pg->fd >= 0) { + PgVFS *pgvfs = fd->ctx->vfs->instance; + lo_close(pgvfs->connection, pg->fd); + } + pool_free(pool, pg); pool_free(pool, fd); }
--- a/src/server/plugins/postgresql/vfs.h Tue Feb 01 20:07:42 2022 +0100 +++ b/src/server/plugins/postgresql/vfs.h Thu Feb 03 17:26:08 2022 +0100 @@ -33,6 +33,7 @@ #include "../../public/vfs.h" #include <libpq-fe.h> +#include <libpq/libpq-fs.h> #ifdef __cplusplus extern "C" { @@ -47,6 +48,8 @@ int64_t resource_id; int64_t parent_id; WSBool iscollection; + Oid oid; + int fd; struct stat s; } PgFile; @@ -73,6 +76,7 @@ const char *path, int64_t *parent_id, int64_t *resource_id, + Oid *oid, const char **resource_name, WSBool *iscollection, struct stat *s);