Add flat file manager (need testing)
authorteodor <teodor>
Mon, 4 Oct 2004 17:57:14 +0000 (17:57 +0000)
committerteodor <teodor>
Mon, 4 Oct 2004 17:57:14 +0000 (17:57 +0000)
Makefile
flatdb.c [new file with mode: 0644]
flatdb.h [new file with mode: 0644]

index c10b9ed..e58d726 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ LIB=-L. -ltedtools -lm
 
 OBJS=tlog.o tmalloc.o tools.o prs_hmap.o sfxstr.o \
        regis.o prs_inf.o shmem.o tcp.o udp.o connpool.o \
-       psort.o
+       psort.o flatdb.o
 PROGS=sfxtest hextest inftest kilter psortex
 
 .SUFFIXES: .o.c
diff --git a/flatdb.c b/flatdb.c
new file mode 100644 (file)
index 0000000..eebbeee
--- /dev/null
+++ b/flatdb.c
@@ -0,0 +1,266 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "tlog.h"
+#include "tmalloc.h"
+
+#include "flatdb.h"
+
+static FDBFreeSpace*
+findFreeSpace(FDB *db, size_t length) {
+       FDBFreeSpace *ptr = db->space;
+       
+       while(ptr && ptr - db->space < db->listcur) {
+               if ( ptr->length >= length )
+                       return ptr; 
+               ptr++;
+       }
+
+       return NULL; 
+}
+
+static int
+cmpFS(const void* a, const void* b) {
+       if ( ((FDBFreeSpace*)a)->offset == ((FDBFreeSpace*)b)->offset )
+               return 0;
+       return ( ((FDBFreeSpace*)a)->offset > ((FDBFreeSpace*)b)->offset ) ? 1 : -1;
+}
+
+void
+FDBVacuumFreeSpace(FDB *db) {
+       FDBFreeSpace *ptr=db->space+1, *ok=db->space;
+       if ( db->listcur < 2 )
+               return;
+
+       qsort( db->space, db->listcur, sizeof(FDBFreeSpace), cmpFS);
+
+       while( ptr - db->space < db->listcur ) {
+               tassert( ok->offset + ok->length <= ptr->offset );
+               if ( ok->offset + ok->length == ptr->offset || ptr->length==0 ) {
+                       ok->length += ptr->length;
+               } else {
+                       ok++;
+                       if ( ok != ptr-1 )
+                               memcpy(ok, ptr, sizeof(FDBFreeSpace));   
+               }
+               ptr++;
+       }
+
+       db->listcur = ok - db->space + 1;       
+}
+
+int 
+FDBOpen(FDB *db, char *file, int readonly) {
+       FDBHeader header;
+       int rc;
+
+       memset(db, 0, sizeof(FDB));
+
+       if ( readonly ) {
+               db->readonly=1;
+               db->fd = open(file, O_RDONLY | O_SHLOCK);
+       } else {
+               db->fd = open(file, O_CREAT | O_RDWR | O_EXLOCK, 0666);
+       }
+
+       if ( db->fd < 0 ) {
+               memset(db, 0, sizeof(FDB));
+               tlog(TL_CRIT,"FDBOpen: open failed: %s", strerror(errno));
+               return FDB_ERROR;
+       }
+
+       rc = read(db->fd, &header, sizeof(FDBHeader));
+
+       if ( rc<0 ) {
+               close(db->fd);
+               tlog(TL_CRIT,"FDBOpen: read failed: %s", strerror(errno));
+               return FDB_ERROR;
+       } else if ( rc==0 ) {
+               memset(&header, 0, sizeof(FDBHeader));
+       } else if ( rc != sizeof(FDBHeader) ) {
+               close(db->fd);
+               tlog(TL_CRIT,"FDBOpen: header fault: %d bytes only", rc);
+               return FDB_ERROR;
+       } else if ( header.isopened ) {
+               close(db->fd);
+               tlog(TL_CRIT,"FDBOpen: file wasn't closed correctly");
+               return FDB_ERROR;
+       }
+               
+       
+       if ( !db->readonly ) {
+               if ( header.freespace ) {
+                       db->listlen = db->listcur = (header.lenfreespace / sizeof(FDBFreeSpace));
+                       db->space = (FDBFreeSpace*)tmalloc( header.lenfreespace + sizeof(FDBFreeSpace) );
+               
+                       if ( lseek(db->fd, header.freespace, SEEK_SET)!=header.freespace || 
+                                       read( db->fd, db->space,  header.lenfreespace ) !=  header.lenfreespace ) {
+                               close(db->fd);
+                               tlog(TL_CRIT,"FDBOpen: free space read failed: %s", strerror(errno));
+                               return FDB_ERROR;
+                       }
+               } else {
+                       db->listlen = 8;
+                       db->space = (FDBFreeSpace*)tmalloc( db->listlen*sizeof(FDBFreeSpace) );
+               }       
+
+               header.freespace = 0;
+               header.lenfreespace = 0;
+               header.isopened = 1;
+
+               if ( lseek(db->fd, 0, SEEK_SET)!=0 || write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) ) {
+                       close(db->fd);
+                       if ( db->space ) tfree( db->space );
+                       tlog(TL_CRIT,"FDBOpen: can't modify header: %s", strerror(errno));
+                       return FDB_ERROR;
+               }
+       }       
+
+       return FDB_OK;
+}
+
+
+int
+FDBClose(FDB *db) {
+       if ( !db->readonly) {
+               FDBHeader header;
+
+               memset(&header,0,sizeof(FDBHeader));
+
+               if ( db->listcur ) {
+                       FDBFreeSpace    *ptr;
+
+                       vacuumFreeSpace(db);
+                       header.lenfreespace = sizeof(FDBFreeSpace)*db->listcur;
+                       ptr = findFreeSpace( db, header.lenfreespace );
+               
+                       if ( ptr ) {
+                               header.freespace = ptr->offset;
+                               if ( lseek(db->fd, ptr->offset, SEEK_SET) != ptr->offset )
+                                       tlog(TL_CRIT|TL_EXIT,"FDBClose: lseek failed: %s", strerror(errno));
+                       } else {
+                               if ( (header.freespace = lseek(db->fd, 0, SEEK_END)) < 0 ) 
+                                       tlog(TL_CRIT|TL_EXIT,"FDBClose: lseek failed: %s", strerror(errno)); 
+                       }
+
+                       if ( write(db->fd, db->space, header.lenfreespace) != header.lenfreespace )
+                               tlog(TL_CRIT|TL_EXIT,"FDBClose: write failed: %s", strerror(errno));
+               }
+
+               header.isopened=0;
+
+               if ( lseek(db->fd,0,SEEK_SET)!=0 || write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) )
+                       tlog(TL_CRIT|TL_EXIT,"FDBClose: header write  failed: %s", strerror(errno)); 
+       }
+
+       close(db->fd);
+
+       if ( db->space )
+               tfree( db->space );
+
+       return FDB_OK;
+}
+
+static int
+readLen(FDB *db, off_t offset, size_t *size) { 
+       if ( lseek(db->fd,offset,SEEK_SET)!=offset)
+               return FDB_ERROR;
+       
+       if ( read(db->fd,size,sizeof(size_t)) != sizeof(size_t) )
+               return FDB_ERROR;
+
+       return FDB_OK;
+}
+
+int
+FDBDelete(FDB *db, off_t offset, size_t length) {
+       if ( db->readonly )
+               return FDB_ERROR;
+
+       if ( length==0 ) 
+               if ( readLen(db, offset, &length) != FDB_OK )
+                       return FDB_ERROR;
+
+       if ( db->listcur >= db->listlen ) {
+               db->listlen *= 2;
+               db->space = (FDBFreeSpace*) trealloc( db->space, db->listlen * sizeof(FDBFreeSpace) );
+       }
+
+       db->space[ db->listcur ].offset=offset;
+       db->space[ db->listcur ].length=length;
+
+       db->listcur++;
+
+       return FDB_OK;
+}
+
+
+int
+FDBGet(FDB *db, off_t offset, size_t length, FDBRecord **record) {
+       size_t rc;
+
+       *record=NULL;
+
+       if ( db->readonly )
+               return FDB_ERROR;
+
+       if ( length==0 )
+               if ( readLen(db, offset, &length) != FDB_OK )
+                       return FDB_ERROR;
+
+       *record = (FDBRecord*)tmalloc( length );
+
+       if ( lseek(db->fd,offset,SEEK_SET)!=offset)
+               return FDB_ERROR;
+
+       if ( (rc=read(db->fd,*record,length)) != length ) {
+               (*record)->length = rc;
+               tlog(TL_CRIT,"FDBGet: read (%d bytes) less than needed (%d bytes): %s", rc, length, strerror(errno));
+               return FDB_INCORRECT;
+       }
+
+       if ( (*record)->length != length ) {
+               tlog(TL_ALARM, "FDBGet: wrong length in opts: %d bytes and %d bytes really", length, (*record)->length);
+               if ( (*record)->length > length ) {
+                       rc = (*record)->length;
+                       tfree( *record );
+                       return FDBGet(db, offset, rc, record);
+               }
+       } 
+
+       return FDB_OK;
+}
+        
+               
+int 
+FDBPut(FDB *db, FDBRecord *record, off_t *offset ) {
+       FDBFreeSpace *ptr;
+
+       if ( db->readonly )
+               return FDB_ERROR;
+
+       ptr = findFreeSpace( db, record->length ); 
+       if ( ptr ) {
+               *offset = ptr->offset;
+               ptr->length -= record->length;
+               if ( ptr->length == 0 ) 
+                       vacuumFreeSpace(db);
+               if ( lseek(db->fd, *offset, SEEK_SET) != *offset ) 
+                       tlog(TL_CRIT|TL_EXIT,"FDBPut: lseek failed: %s", strerror(errno)); 
+       } else {
+               if ( (*offset = lseek(db->fd, 0, SEEK_END)) < 0 ) 
+                       tlog(TL_CRIT|TL_EXIT,"FDBPut: lseek failed: %s", strerror(errno)); 
+       }
+
+       if ( write(db->fd, record, record->length) != record->length ) 
+               tlog(TL_CRIT|TL_EXIT,"FDBPut: write lseek failed: %s", strerror(errno));
+
+       return FDB_OK;
+
+}
+
+
diff --git a/flatdb.h b/flatdb.h
new file mode 100644 (file)
index 0000000..16ef5c5
--- /dev/null
+++ b/flatdb.h
@@ -0,0 +1,47 @@
+#ifndef __FLAT_DB__
+#define __FLAT_DB__
+
+#include <sys/types.h>
+
+typedef struct {
+       off_t   freespace;
+       size_t  lenfreespace;
+       u_int32_t
+               unused:31, 
+               isopened:1;
+} FDBHeader;
+
+typedef struct {
+       size_t  length;
+       char    *data;
+} FDBRecord;
+
+#define RECHDRSZ       (sizeof(size_t))
+
+typedef struct {
+       off_t   offset;
+       size_t  length;
+} FDBFreeSpace;
+
+typedef struct {
+       int     fd; /* file descriptor */
+       u_int32_t       unused:31,
+                       readonly:1;
+       u_int32_t       listlen;
+       u_int32_t       listcur;
+       FDBFreeSpace    *space;
+} FDB;
+
+int FDBOpen(FDB *db, char *file, int readonly);
+int FDBClose(FDB *db);
+int FDBPut(FDB *db, FDBRecord *record /*in*/, off_t *offset /*out*/);
+int FDBGet(FDB *db, off_t offset /* in */, size_t length /*in, may =0, then stored size*/, FDBRecord **record /*out*/);
+int FDBDelete(FDB *db, off_t offset /* in */, size_t length /*in, may =0, then stored size*/ );
+void FDBVacuumFreeSpace(FDB *db); 
+
+#define FDB_OK         0
+#define FDB_NOTFOUND   1
+#define FDB_ERROR      2
+#define FDB_INCORRECT  3
+
+#endif