use psplay trees for the filedescriptor registry

This commit is contained in:
Christian Thaeter 2008-08-12 11:39:35 +02:00
parent c3e2941eb8
commit a1bd3ee1f5
4 changed files with 87 additions and 47 deletions

View file

@ -21,7 +21,6 @@
#include "lib/mutex.h"
#include "lib/safeclib.h"
#include "lib/cuckoo.h"
#include "backend/file.h"
#include "backend/filedescriptor.h"
@ -42,46 +41,50 @@ NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore.
*/
static Cuckoo registry = NULL;
static PSplay registry = NULL;
static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER};
/*
* setup hashing and compare functions for cuckoo hashing
*/
static size_t
h1 (const void* item, const uint32_t r)
{
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>7)^r;
}
static size_t
h2 (const void* item, const uint32_t r)
{
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>5)^r;
}
static size_t
h3 (const void* item, const uint32_t r)
{
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>3)^r;
}
static int
cmp (const void* keya, const void* keyb)
cmp_fn (const void* keya, const void* keyb)
{
const LumieraFiledescriptor a = *(const LumieraFiledescriptor*)keya;
const LumieraFiledescriptor b = *(const LumieraFiledescriptor*)keyb;
return a->stat.st_dev == b->stat.st_dev && a->stat.st_ino == b->stat.st_ino
&& (a->flags&LUMIERA_FILE_MASK) == (b->flags&LUMIERA_FILE_MASK);
const LumieraFiledescriptor a = (const LumieraFiledescriptor)keya;
const LumieraFiledescriptor b = (const LumieraFiledescriptor)keyb;
if (a->stat.st_dev < b->stat.st_dev)
return -1;
else if (a->stat.st_dev > b->stat.st_dev)
return 1;
if (a->stat.st_ino < b->stat.st_ino)
return -1;
else if (a->stat.st_ino > b->stat.st_ino)
return 1;
if ((a->flags&LUMIERA_FILE_MASK) < (b->flags&LUMIERA_FILE_MASK))
return -1;
else if ((a->flags&LUMIERA_FILE_MASK) > (b->flags&LUMIERA_FILE_MASK))
return 1;
return 0;
}
static void
delete_fn (PSplaynode node)
{
lumiera_filedescriptor_delete ((LumieraFiledescriptor) node);
}
static const void*
key_fn (const PSplaynode node)
{
return node;
}
void
lumiera_filedescriptor_registry_init (void)
{
@ -89,9 +92,7 @@ lumiera_filedescriptor_registry_init (void)
TRACE (filedescriptor);
REQUIRE (!registry);
registry = cuckoo_new (h1, h2, h3, cmp,
sizeof (LumieraFiledescriptor),
3);
registry = psplay_new (cmp_fn, key_fn, delete_fn);
if (!registry)
LUMIERA_DIE (NO_MEMORY);
@ -103,12 +104,12 @@ void
lumiera_filedescriptor_registry_destroy (void)
{
TRACE (filedescriptor);
REQUIRE (!cuckoo_nelements (registry));
REQUIRE (!psplay_nelements (registry));
RESOURCE_FORGET (filedescriptor, registry_mutex.rh);
if (registry)
cuckoo_free (registry);
psplay_destroy (registry);
registry = NULL;
}
@ -162,10 +163,9 @@ lumiera_filedescriptor_acquire (const char* name, int flags)
}
/* lookup/create descriptor */
dest = &fdesc;
LumieraFiledescriptor* found = cuckoo_find (registry, &dest);
dest = (LumieraFiledescriptor) psplay_find (registry, &fdesc, 100);
if (!found)
if (!dest)
{
TRACE (filedescriptor, "Descriptor not found");
@ -173,12 +173,11 @@ lumiera_filedescriptor_acquire (const char* name, int flags)
if (!dest)
goto error;
cuckoo_insert (registry, &dest);
psplay_insert (registry, &dest->node, 100);
}
else
{
TRACE (filedescriptor, "Descriptor already existing");
dest = *found;
++dest->refcount;
}
error: ;
@ -191,7 +190,7 @@ lumiera_filedescriptor_acquire (const char* name, int flags)
void
lumiera_filedescriptor_release (LumieraFiledescriptor self)
{
TRACE (filedescriptor);
TRACE (filedescriptor, "%p", self);
if (!--self->refcount)
lumiera_filedescriptor_delete (self);
}
@ -203,6 +202,7 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template)
LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor));
TRACE (filedescriptor, "at %p", self);
psplaynode_init (&self->node);
self->stat = template->stat;
self->flags = template->flags;
@ -224,7 +224,7 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self)
{
REQUIRE (self->refcount == 0);
cuckoo_remove (registry, cuckoo_find (registry, &self));
psplay_remove (registry, &self->node);
TODO ("destruct other members (WIP)");

View file

@ -23,6 +23,7 @@
#define LUMIERA_FILEDESCRIPTOR_H
#include "lib/mutex.h"
#include "lib/psplay.h"
#include <sys/types.h>
@ -47,7 +48,8 @@ typedef lumiera_filedescriptor* LumieraFiledescriptor;
struct lumiera_filedescriptor_struct
{
struct stat stat; /* create after first open, maintained metadata, MUST BE FIRST! */
psplaynode node; /* node for the lookup tree */
struct stat stat; /* create after first open, maintained metadata */
int flags; /* open flags, must be masked for reopen */
lumiera_mutex lock; /* locks operations on this file descriptor */
unsigned refcount; /* reference counter, all users sans registry */

View file

@ -13,6 +13,18 @@ END
rm ,tmp_testfile
echo testdata > ,tmp_testfile1
echo testdata > ,tmp_testfile2
echo testdata > ,tmp_testfile3
TEST "acquire 3 files" acquire_existing_3files <<END
return: 0
END
rm ,tmp_testfile1
rm ,tmp_testfile2
rm ,tmp_testfile3
TEST "acquire file, creating it" acquire_create <<END
return: 0
END

View file

@ -57,6 +57,32 @@ TEST ("acquire_existing_again")
return 1;
}
TEST ("acquire_existing_3files")
{
lumiera_backend_init ();
LumieraFiledescriptor descriptor1 = lumiera_filedescriptor_acquire (",tmp_testfile1", LUMIERA_FILE_READONLY);
LumieraFiledescriptor descriptor2 = lumiera_filedescriptor_acquire (",tmp_testfile2", LUMIERA_FILE_READONLY);
LumieraFiledescriptor descriptor3 = lumiera_filedescriptor_acquire (",tmp_testfile3", LUMIERA_FILE_READONLY);
if (descriptor1)
lumiera_filedescriptor_release (descriptor1);
if (descriptor2)
lumiera_filedescriptor_release (descriptor2);
if (descriptor3)
lumiera_filedescriptor_release (descriptor3);
if (descriptor1 && descriptor2 && descriptor3)
{
lumiera_backend_destroy ();
return 0;
}
else
return 1;
}
TEST ("acquire_create")
{
lumiera_backend_init ();