#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
#include "tlog.h"
#include "tmalloc.h"
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
if ( readonly ) {
db->readonly=1;
- db->fd = open(file, O_RDONLY | O_SHLOCK);
+ db->fd = open(file, O_RDONLY);
+ if ( db->fd < 0 ) {
+ tlog(TL_CRIT,"FDBOpen: open failed: %s",strerror(errno));
+ return FDB_ERROR;
+ }
+ if ( flock( db->fd, LOCK_SH ) < 0 ) {
+ tlog(TL_CRIT,"FDBOpen: flock failed: %s",strerror(errno));
+ close(db->fd);
+ return FDB_ERROR;
+ }
} 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;
+ db->fd = open(file, O_CREAT | O_RDWR, 0666);
+ if ( db->fd < 0 ) {
+ tlog(TL_CRIT,"FDBOpen: open failed: %s",strerror(errno));
+ return FDB_ERROR;
+ }
+ if ( flock( db->fd, LOCK_EX ) < 0 ) {
+ tlog(TL_CRIT,"FDBOpen: flock failed: %s",strerror(errno));
+ close(db->fd);
+ return FDB_ERROR;
+ }
}
rc = read(db->fd, &header, sizeof(FDBHeader));
if ( rc<0 ) {
+ flock( db->fd, LOCK_UN );
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) ) {
+ flock( db->fd, LOCK_UN );
close(db->fd);
tlog(TL_CRIT,"FDBOpen: header fault: %d bytes only", rc);
return FDB_ERROR;
} else if ( header.isopened ) {
+ flock( db->fd, LOCK_UN );
close(db->fd);
tlog(TL_CRIT,"FDBOpen: file wasn't closed correctly");
return FDB_ERROR;
if ( lseek(db->fd, header.freespace, SEEK_SET)!=header.freespace ||
read( db->fd, db->space, header.lenfreespace ) != header.lenfreespace ) {
+ flock( db->fd, LOCK_UN );
close(db->fd);
tlog(TL_CRIT,"FDBOpen: free space read failed: %s", strerror(errno));
return FDB_ERROR;
if ( lseek(db->fd, 0, SEEK_SET)!=0 ||
write(db->fd, &header, sizeof(FDBHeader)) != sizeof(FDBHeader) ||
fsync(db->fd) ) {
+ flock( db->fd, LOCK_UN );
close(db->fd);
if ( db->space ) tfree( db->space );
tlog(TL_CRIT,"FDBOpen: can't modify header: %s", strerror(errno));
FDBVacuumFreeSpace(db);
header.lenfreespace = sizeof(FDBFreeSpace)*db->listcur;
+
ptr = findFreeSpace( db, header.lenfreespace );
if ( ptr ) {
tlog(TL_CRIT|TL_EXIT,"FDBClose: header write failed: %s", strerror(errno));
}
+ flock( db->fd, LOCK_UN );
close(db->fd);
if ( db->space )
if ( readLen(db, offset, &length) != FDB_OK )
return FDB_ERROR;
- addFreeSpace(db, offset, length);
+ addFreeSpace(db, offset, PTRALIGN(length));
return FDB_OK;
}
*record=NULL;
- if ( db->readonly )
+ if ( offset < sizeof(FDBHeader) )
return FDB_ERROR;
if ( length==0 )
int
FDBPut(FDB *db, FDBRecord *record, off_t *offset ) {
FDBFreeSpace *ptr;
+ size_t aligned;
if ( db->readonly )
return FDB_ERROR;
- ptr = findFreeSpace( db, record->length );
+ aligned = PTRALIGN(record->length);
+
+ ptr = findFreeSpace( db, aligned );
if ( ptr ) {
*offset = ptr->offset;
- ptr->offset += record->length;
ptr->length -= record->length;
- if ( ptr->length == 0 )
- FDBVacuumFreeSpace(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 {
if ( write(db->fd, record, record->length) != record->length )
tlog(TL_CRIT|TL_EXIT,"FDBPut: write failed: %s", strerror(errno));
+ if ( record->length != aligned ) {
+ char buf[] = {0, 0, 0, 0, 0, 0, 0, 0};
+ if ( write(db->fd, buf, aligned - record->length) != (aligned - record->length) )
+ tlog(TL_CRIT|TL_EXIT,"FDBPut: write failed: %s", strerror(errno));
+ }
return FDB_OK;
-
}