summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <abaumann@yahoo.com>2013-04-15 18:52:51 +0200
committerAndreas Baumann <abaumann@yahoo.com>2013-04-15 18:52:51 +0200
commit906665d02eefdc98b93edab645e8f0c08c5dfdf3 (patch)
tree0256d5dee7a609da5f179c772cb78a8258663d61
parent75d12c2bd82cccec8847703e95ceec4fef9588f2 (diff)
downloadpgfuse-906665d02eefdc98b93edab645e8f0c08c5dfdf3.tar.gz
pgfuse-906665d02eefdc98b93edab645e8f0c08c5dfdf3.tar.bz2
started to rewrite, removed dependecy on shell/Perl
resulting a fictive number for free files and free blocks for now added test cases removed function.sql
-rw-r--r--TODO5
-rw-r--r--function.sql21
-rw-r--r--pgfuse.c89
-rw-r--r--pgsql.c60
-rw-r--r--pgsql.h8
-rw-r--r--tests/Makefile7
6 files changed, 104 insertions, 86 deletions
diff --git a/TODO b/TODO
index 739f1a8..9aa7191 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,11 @@
TODO list (in order of priority)
---------
+- integrate statfs patch:
+ - Can't do this, as the db user must be underprivileged:
+ show data_directory;
+ ERROR: must be superuser to examine "data_directory"
+ - no Perl, Shell, Posix df dependency
- handling of most file system metadata
- ownership: how is this done depending on
per-user or root mounts? think about security
diff --git a/function.sql b/function.sql
deleted file mode 100644
index 59746a1..0000000
--- a/function.sql
+++ /dev/null
@@ -1,21 +0,0 @@
-CREATE LANGUAGE plperlu;
-CREATE OR REPLACE FUNCTION db_disk_free()
- RETURNS bigint AS
-$BODY$
-# Get size of data_directory partition
-# this uses UNIX df(1) command
-
-# reported by df(1)
-my $df=`df -B1 -a -P \$(psql -c "show data_directory;" -t)`;
-my @df=split(/[\n\r]+/,$df);
-shift @df;
-for my $l (@df) {
- my @a=split(/\s+/,$l);
- return $a[3];
-}
-
-return undef;
-$BODY$
- LANGUAGE 'plperlu' VOLATILE
- COST 1000;
-COMMENT ON FUNCTION db_disk_free() IS 'Get free disck space of data_directory partition';
diff --git a/pgfuse.c b/pgfuse.c
index 1f7a391..7af2d18 100644
--- a/pgfuse.c
+++ b/pgfuse.c
@@ -938,61 +938,80 @@ static int pgfuse_statfs( const char *path, struct statvfs *buf )
PGconn *conn;
- int64_t fs_size, fs_used, fs_free, fs_avail;
+ int64_t blocks_total, blocks_used, blocks_free, blocks_avail;
+ int64_t files_total, files_used, files_free, files_avail;
if( data->verbose ) {
syslog( LOG_INFO, "Statfs called on '%s', thread #%u",
data->mountpoint, THREAD_ID );
}
-
- /* Note: f_frsize, f_favail, f_fsid and f_flag are currently ignored by FUSE */
-
+
memset( buf, 0, sizeof( struct statvfs ) );
- buf->f_bsize = data->block_size;
- buf->f_frsize = data->block_size;
-
ACQUIRE( conn );
PSQL_BEGIN( conn );
- fs_free = psql_get_fs_free( conn );
-
- if( fs_free < 0 ) {
- fs_free = INT_MAX;
- } else {
- fs_free = fs_free / data->block_size;
+ /* blocks */
+
+ blocks_free = psql_get_fs_blocks_free( conn );
+ if( blocks_free < 0 ) {
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -blocks_free;
+ }
- };
+ blocks_used = psql_get_fs_blocks_used( conn );
+ if( blocks_used < 0 ) {
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -blocks_used;
+ }
+
+ blocks_total = blocks_free + blocks_used;
+ blocks_avail = blocks_free;
+
+ /* inodes */
- fs_used = psql_get_fs_used( conn );
+ files_free = psql_get_fs_blocks_free( conn );
+ if( files_free < 0 ) {
+ PSQL_ROLLBACK( conn ); RELEASE( conn );
+ return -files_free;
+ }
- if( fs_used < 0 ) {
+ files_used = psql_get_fs_files_used( conn );
+ if( files_used < 0 ) {
PSQL_ROLLBACK( conn ); RELEASE( conn );
- fs_used = INT_MAX;
- fs_size = INT_MAX;
- fs_free = INT_MAX;
- fs_avail = INT_MAX;
- } else {
- fs_used = fs_used / data->block_size;
- fs_size = fs_free + fs_used;
- fs_avail = fs_free;
- };
+ return -files_used;
+ }
- PSQL_COMMIT( conn ); RELEASE( conn );
+ files_total = files_free + files_used;
+ files_avail = files_free;
- /* Note: it's hard to tell how much space is left in the database
- * and how big it is
- */
- buf->f_blocks = fs_size;
- buf->f_bfree = fs_free;
- buf->f_bavail = fs_avail;
- buf->f_files = INT_MAX;
- buf->f_ffree = INT_MAX;
- buf->f_favail = INT_MAX;
+ if( data->verbose ) {
+ syslog( LOG_ERR, "Stats for '%s' are (%jd blocks total, %jd used, %jd free, "
+ "%jd files total, %jd files used, %jd files free, thread #%u",
+ data->mountpoint,
+ blocks_total, blocks_used, blocks_free,
+ files_total, files_used, files_free,
+ THREAD_ID );
+ }
+
+ /* fill statfs structure */
+
+ /* Note: f_frsize, f_favail, f_fsid and f_flag are currently ignored by FUSE */
+ buf->f_bsize = data->block_size;
+ buf->f_frsize = data->block_size;
+ buf->f_blocks = blocks_total;
+ buf->f_bfree = blocks_free;
+ buf->f_bavail = blocks_avail;
+ buf->f_files = files_total;
+ buf->f_ffree = files_free;
+ buf->f_favail = files_avail;
+ buf->f_fsid = 0x4FE3A364;
if( data->read_only ) {
buf->f_flag |= ST_RDONLY;
}
buf->f_namemax = MAX_FILENAME_LENGTH;
+
+ PSQL_COMMIT( conn ); RELEASE( conn );
return 0;
}
diff --git a/pgsql.c b/pgsql.c
index 6b7a263..242c953 100644
--- a/pgsql.c
+++ b/pgsql.c
@@ -25,6 +25,7 @@
#include <arpa/inet.h> /* for htonl, ntohl */
#include <stdint.h> /* for uint64_t */
#include <inttypes.h> /* for PRIxxx macros */
+#include <values.h> /* for INT_MAX */
#include "endian.h" /* for be64toh and htobe64 */
@@ -928,54 +929,61 @@ size_t psql_get_block_size( PGconn *conn, const size_t block_size )
return db_block_size;
}
-size_t psql_get_fs_used( PGconn *conn )
+size_t psql_get_fs_blocks_used( PGconn *conn )
{
PGresult *res;
char *data;
- size_t fs_used;
- res = PQexec( conn, "SELECT SUM(size) FROM dir;" );
+ size_t used;
+
+ res = PQexec( conn, "SELECT (SELECT COUNT(*) FROM data) + (SELECT COUNT(*) FROM dir)" );
if( PQresultStatus( res ) != PGRES_TUPLES_OK ) {
- syslog( LOG_ERR, "Error in psql_get_fs_used: %s", PQerrorMessage( conn ) );
+ syslog( LOG_ERR, "Error in psql_get_fs_blocks_used: %s", PQerrorMessage( conn ) );
PQclear( res );
return -EIO;
}
- /* empty, this is ok, any blocksize acceptable after initialization */
- if( PQntuples( res ) == 0 ) {
- PQclear( res );
- return 0;
- }
-
+ /* we calculate the number of blocks occupied by all data entries
+ * plus all "indoes" (in our case entries in dir),
+ * more like a filesystem would do it. Returning blocks as this is
+ * harder to overflow a size_t (in case it's 32-bit, modern
+ * systems shouldn't care). It's slower though
+ */
data = PQgetvalue( res, 0, 0 );
- fs_used = atol( data );
+ used = atoi( data );
PQclear( res );
- return fs_used;
+ return used;
}
-size_t psql_get_fs_free( PGconn *conn )
+size_t psql_get_fs_blocks_free( PGconn *conn )
{
- PGresult *res;
- char *data;
- size_t fs_free;
- res = PQexec( conn, "SELECT db_disk_free();" );
- if( PQresultStatus( res ) != PGRES_TUPLES_OK ) {
- syslog( LOG_ERR, "Error in psql_get_fs_free: %s", PQerrorMessage( conn ) );
- PQclear( res );
- return -EIO;
- }
+ return 9999;
+}
- /* empty, this is ok, any blocksize acceptable after initialization */
- if( PQntuples( res ) == 0 ) {
+size_t psql_get_fs_files_used( PGconn *conn )
+{
+ PGresult *res;
+ char *data;
+ size_t used;
+
+ res = PQexec( conn, "SELECT COUNT(*) FROM dir" );
+ if( PQresultStatus( res ) != PGRES_TUPLES_OK ) {
+ syslog( LOG_ERR, "Error in psql_get_fs_files_used: %s", PQerrorMessage( conn ) );
PQclear( res );
return -EIO;
}
data = PQgetvalue( res, 0, 0 );
- fs_free = atol( data );
+ used = atoi( data );
PQclear( res );
- return fs_free;
+ return used;
}
+
+size_t psql_get_fs_files_free( PGconn *conn )
+{
+ return 9999;
+}
+
diff --git a/pgsql.h b/pgsql.h
index 29f9db9..3738894 100644
--- a/pgsql.h
+++ b/pgsql.h
@@ -98,8 +98,12 @@ int psql_rename( PGconn *conn, const int64_t from_id, const int64_t from_parent_
size_t psql_get_block_size( PGconn *conn, const size_t block_size );
-size_t psql_get_fs_used( PGconn *conn );
+size_t psql_get_fs_blocks_used( PGconn *conn );
-size_t psql_get_fs_free( PGconn *conn );
+size_t psql_get_fs_blocks_free( PGconn *conn );
+
+size_t psql_get_fs_files_used( PGconn *conn );
+
+size_t psql_get_fs_files_free( PGconn *conn );
#endif
diff --git a/tests/Makefile b/tests/Makefile
index b8dd4e3..f44570f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -48,8 +48,6 @@ test: testfsync testpgsql testtypes testbigfile
-stat mnt/dir/dir4/bfile
-stat mnt/dir/dir4
-stat mnt/dir/dir4/dlink
- # show filesystem stats (statvfs)
- -stat -f mnt
# expect success, truncate a file (grow and shrink)
-touch mnt/trunc
-ls -al mnt/trunc
@@ -61,6 +59,11 @@ test: testfsync testpgsql testtypes testbigfile
# expect success, write a sparse big file
-./testbigfile
-ls -al mnt/testbigfile.data
+ # show filesystem stats (statvfs)
+ -stat -f mnt
+ # the more human readable output of statvfs
+ -df -h mnt
+ -df -i mnt
# END: unmount FUSE file system
fusermount -u mnt