Add linux compatibility
[tedtools.git] / flatdb.c
index eebbeee..79a1ec6 100644 (file)
--- a/flatdb.c
+++ b/flatdb.c
@@ -1,9 +1,39 @@
+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *        may be used to endorse or promote products derived from this software
+ *        without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include "tlog.h"
 #include "tmalloc.h"
@@ -23,6 +53,19 @@ findFreeSpace(FDB *db, size_t length) {
        return NULL; 
 }
 
+static void
+addFreeSpace(FDB *db, off_t offset, size_t length) {
+       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++;
+}
+
 static int
 cmpFS(const void* a, const void* b) {
        if ( ((FDBFreeSpace*)a)->offset == ((FDBFreeSpace*)b)->offset )
@@ -33,24 +76,33 @@ cmpFS(const void* a, const void* b) {
 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);
 
+       /* merge spaces */
        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 {
+                       ptr->length=0;
+               } else
                        ok++;
-                       if ( ok != ptr-1 )
-                               memcpy(ok, ptr, sizeof(FDBFreeSpace));   
-               }
                ptr++;
        }
 
-       db->listcur = ok - db->space + 1;       
+       /* remove void spaces */
+       ptr = ok = db->space;
+       while( ptr - db->space < db->listcur ) {
+               if ( ptr->length != 0 ) {
+                       if ( ok != ptr )
+                               memcpy(ok,ptr,sizeof(FDBFreeSpace));
+                       ok++;
+               }
+               ptr++;
+       }
+       db->listcur = ok - db->space;   
 }
 
 int 
@@ -103,6 +155,7 @@ FDBOpen(FDB *db, char *file, int readonly) {
                                tlog(TL_CRIT,"FDBOpen: free space read failed: %s", strerror(errno));
                                return FDB_ERROR;
                        }
+                       FDBVacuumFreeSpace(db);
                } else {
                        db->listlen = 8;
                        db->space = (FDBFreeSpace*)tmalloc( db->listlen*sizeof(FDBFreeSpace) );
@@ -112,7 +165,9 @@ FDBOpen(FDB *db, char *file, int readonly) {
                header.lenfreespace = 0;
                header.isopened = 1;
 
-               if ( lseek(db->fd, 0, SEEK_SET)!=0 || write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) ) {
+               if ( lseek(db->fd, 0, SEEK_SET)!=0 || 
+                               write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) || 
+                               fsync(db->fd) ) {
                        close(db->fd);
                        if ( db->space ) tfree( db->space );
                        tlog(TL_CRIT,"FDBOpen: can't modify header: %s", strerror(errno));
@@ -134,7 +189,8 @@ FDBClose(FDB *db) {
                if ( db->listcur ) {
                        FDBFreeSpace    *ptr;
 
-                       vacuumFreeSpace(db);
+                       FDBVacuumFreeSpace(db);
+
                        header.lenfreespace = sizeof(FDBFreeSpace)*db->listcur;
                        ptr = findFreeSpace( db, header.lenfreespace );
                
@@ -144,7 +200,9 @@ FDBClose(FDB *db) {
                                        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)); 
+                                       tlog(TL_CRIT|TL_EXIT,"FDBClose: lseek failed: %s", strerror(errno));
+                               header.lenfreespace += sizeof(FDBFreeSpace); 
+                               addFreeSpace(db, header.freespace, header.lenfreespace); 
                        }
 
                        if ( write(db->fd, db->space, header.lenfreespace) != header.lenfreespace )
@@ -153,7 +211,9 @@ FDBClose(FDB *db) {
 
                header.isopened=0;
 
-               if ( lseek(db->fd,0,SEEK_SET)!=0 || write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) )
+               if ( lseek(db->fd,0,SEEK_SET)!=0 || 
+                               write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) || 
+                               fsync(db->fd))
                        tlog(TL_CRIT|TL_EXIT,"FDBClose: header write  failed: %s", strerror(errno)); 
        }
 
@@ -176,6 +236,7 @@ readLen(FDB *db, off_t offset, size_t *size) {
        return FDB_OK;
 }
 
+
 int
 FDBDelete(FDB *db, off_t offset, size_t length) {
        if ( db->readonly )
@@ -185,15 +246,7 @@ FDBDelete(FDB *db, off_t offset, size_t length) {
                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++;
+       addFreeSpace(db, offset, length);
 
        return FDB_OK;
 }
@@ -205,7 +258,7 @@ FDBGet(FDB *db, off_t offset, size_t length, FDBRecord **record) {
 
        *record=NULL;
 
-       if ( db->readonly )
+       if ( offset < sizeof(FDBHeader) )       
                return FDB_ERROR;
 
        if ( length==0 )
@@ -247,8 +300,12 @@ FDBPut(FDB *db, FDBRecord *record, off_t *offset ) {
        if ( ptr ) {
                *offset = ptr->offset;
                ptr->length -= record->length;
-               if ( ptr->length == 0 ) 
-                       vacuumFreeSpace(db);
+               if ( ptr->length == 0 ) {
+                       if ( (ptr - db->space) + 1 != db->listcur ) 
+                               memmove(ptr, ptr+1, (db->listcur - (ptr - db->space) + 1) * sizeof(FDBFreeSpace));
+                       db->listcur--; 
+               } else
+                       ptr->offset += record->length;
                if ( lseek(db->fd, *offset, SEEK_SET) != *offset ) 
                        tlog(TL_CRIT|TL_EXIT,"FDBPut: lseek failed: %s", strerror(errno)); 
        } else {
@@ -257,7 +314,7 @@ FDBPut(FDB *db, FDBRecord *record, off_t *offset ) {
        }
 
        if ( write(db->fd, record, record->length) != record->length ) 
-               tlog(TL_CRIT|TL_EXIT,"FDBPut: write lseek failed: %s", strerror(errno));
+               tlog(TL_CRIT|TL_EXIT,"FDBPut: write failed: %s", strerror(errno));
 
        return FDB_OK;