minimal working send_file with postgresql vfs webdav

Thu, 03 Feb 2022 17:26:08 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 03 Feb 2022 17:26:08 +0100
branch
webdav
changeset 283
25e5b771677d
parent 282
cfb588e27198
child 284
eab579b8c80d

minimal working send_file with postgresql vfs

doc/development/postgresql_vfs.sql file | annotate | diff | comparison | revisions
doc/development/postgresql_vfs_testdata.sql file | annotate | diff | comparison | revisions
src/server/daemon/resourcepool.c file | annotate | diff | comparison | revisions
src/server/plugins/postgresql/resource.c file | annotate | diff | comparison | revisions
src/server/plugins/postgresql/vfs.c file | annotate | diff | comparison | revisions
src/server/plugins/postgresql/vfs.h file | annotate | diff | comparison | revisions
--- 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);

mercurial