mmap updates/refactoring
This commit is contained in:
parent
9f497cdaa3
commit
db202e298e
5 changed files with 77 additions and 59 deletions
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
|
|
@ -48,14 +49,12 @@ LUMIERA_ERROR_DEFINE (MMAP_SPACE, "Address space exhausted");
|
|||
|
||||
|
||||
LumieraMMap
|
||||
lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t start, size_t size, size_t chunksize)
|
||||
lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size)
|
||||
{
|
||||
TRACE (mmap);
|
||||
|
||||
REQUIRE (self);
|
||||
REQUIRE (file);
|
||||
REQUIRE (acquirer);
|
||||
REQUIRE (llist_is_empty (acquirer));
|
||||
REQUIRE (start >= 0);
|
||||
REQUIRE (size);
|
||||
|
||||
|
|
@ -85,9 +84,10 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t sta
|
|||
if (fd == -1)
|
||||
goto efile;
|
||||
|
||||
void* addr = NULL;
|
||||
void* addr = (void*)-1;
|
||||
off_t begin = 0;
|
||||
size_t length = 0;
|
||||
size_t chunksize = lumiera_file_chunksize_get (file);
|
||||
|
||||
/**
|
||||
* Maintaining the right[tm] mmaping size is a bit tricky:
|
||||
|
|
@ -99,31 +99,35 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t sta
|
|||
* - Requests beyond the file end must ftruncate and map additional pages
|
||||
* - Create the 'refmap' which contains a refounter per chunk
|
||||
**/
|
||||
while (!addr)
|
||||
|
||||
/**
|
||||
* Recovering address space strategies:
|
||||
* mmap() will fail when too much memory got mmaped after some time which is then
|
||||
* recovered in the following way
|
||||
* 1. create a new mmap while the cachelimit is not reached.
|
||||
* 2. All unused mmaps are kept in a mrucache, drop the oldest one.
|
||||
* mmap() still fails..
|
||||
* 3.a When the intented mmaping size is the same as mmap_window_size then reduce (/2) the window size and retry.
|
||||
* 3.b When the intented mmaping size was biggier than mmap_window_size then free more mmaps from the cache.
|
||||
* 4 When the cache is empty (that means all mmaps in use), scan the mmaps in use if they can be reduced
|
||||
* mmap_window_size is already reduced now (half of refmap free from either end)
|
||||
**/
|
||||
enum {
|
||||
FIRST_TRY,
|
||||
DROP_FROM_CACHE,
|
||||
REDUCE_WINDOW,
|
||||
REDUCE_IN_USE,
|
||||
GIVE_UP
|
||||
} strategy = FIRST_TRY;
|
||||
|
||||
while (addr == (void*)-1)
|
||||
{
|
||||
/**
|
||||
* Recovering address space strategies:
|
||||
* mmap() will fail when too much memory got mmaped after some time which is then
|
||||
* recovered in the following way
|
||||
* 1. create a new mmap while the cachelimit is not reached.
|
||||
* 2. All unused mmaps are kept in a mrucache, drop the oldest one.
|
||||
* mmap() still fails..
|
||||
* 3.a When the intented mmaping size is the same as mmap_window_size then reduce (/2) the window size and retry.
|
||||
* 3.b When the intented mmaping size was biggier than mmap_window_size then free more mmaps from the cache.
|
||||
* 4 When the cache is empty (that means all mmaps in use), scan the mmaps in use if they can be reduced
|
||||
* mmap_window_size is already reduced now (half of refmap free from either end)
|
||||
**/
|
||||
enum {
|
||||
FIRST_TRY,
|
||||
DROP_FROM_CACHE,
|
||||
REDUCE_WINDOW,
|
||||
REDUCE_IN_USE,
|
||||
GIVE_UP
|
||||
} strategy = FIRST_TRY;
|
||||
TODO ("check if current mmaped size exceeds configured as_size (as_size be smaller than retrieved from getrlimit())");
|
||||
|
||||
switch (strategy++)
|
||||
{
|
||||
case FIRST_TRY:
|
||||
TRACE (mmap, "FIRST_TRY");
|
||||
/* align begin and end to chunk boundaries */
|
||||
begin = start & ~(chunksize-1);
|
||||
length = ((start+size+chunksize-1) & ~(chunksize-1)) - begin;
|
||||
|
|
@ -142,18 +146,15 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t sta
|
|||
descriptor->stat.st_size = begin+length;
|
||||
descriptor->realsize = start+size;
|
||||
}
|
||||
else
|
||||
{
|
||||
LUMIERA_ERROR_SET (mmap, MMAP_NWRITE);
|
||||
goto ewrite;
|
||||
}
|
||||
}
|
||||
else if (length < (size_t)mmap_window_size)
|
||||
length = mmap_window_size;
|
||||
|
||||
if ((descriptor->flags & O_ACCMODE) == O_RDONLY)
|
||||
/* The last mmaped chunk of a file can be as small as possible when the file is readonly */
|
||||
length = start+size - begin;
|
||||
{
|
||||
/* The last mmaped chunk of a file can be as small as possible when the file is readonly */
|
||||
length = start+size - begin;
|
||||
}
|
||||
break;
|
||||
|
||||
case DROP_FROM_CACHE:
|
||||
|
|
@ -182,6 +183,9 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t sta
|
|||
MAP_SHARED,
|
||||
fd,
|
||||
begin);
|
||||
|
||||
INFO_IF (addr==(void*)-1, mmap, "mmap failed %s", strerror (errno));
|
||||
ENSURE (errno == 0 || errno == ENOMEM, "unexpected mmap error %s", strerror (errno));
|
||||
}
|
||||
|
||||
llist_init (&self->cachenode);
|
||||
|
|
@ -190,11 +194,8 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t sta
|
|||
self->start = begin;
|
||||
self->size = length;
|
||||
self->address = addr;
|
||||
|
||||
self->refmap = lumiera_calloc (length/chunksize, sizeof (unsigned short));
|
||||
|
||||
llist_insert_head (&self->cachenode, acquirer);
|
||||
|
||||
self->refmap = lumiera_calloc ((length-1)/chunksize+1, sizeof (unsigned short));
|
||||
self->refcnt = 1;
|
||||
lumiera_mmapcache_announce (lumiera_mcache, self);
|
||||
|
||||
lumiera_file_handle_release (file);
|
||||
|
|
@ -202,7 +203,6 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t sta
|
|||
|
||||
espace:
|
||||
etruncate:
|
||||
ewrite:
|
||||
efile:
|
||||
lumiera_file_handle_release (file);
|
||||
lumiera_free (self);
|
||||
|
|
@ -210,17 +210,17 @@ lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t sta
|
|||
}
|
||||
|
||||
LumieraMMap
|
||||
lumiera_mmap_new (LumieraFile file, LList acquirer, off_t start, size_t size, size_t chunksize)
|
||||
lumiera_mmap_new (LumieraFile file, off_t start, size_t size)
|
||||
{
|
||||
TRACE (mmap);
|
||||
|
||||
LumieraMMap self = lumiera_mmapcache_mmap_acquire (lumiera_mcache);
|
||||
|
||||
if (lumiera_mmap_init (self, file, acquirer, start, size, chunksize))
|
||||
if (lumiera_mmap_init (self, file, start, size))
|
||||
return self;
|
||||
else
|
||||
{
|
||||
free (self);
|
||||
lumiera_free (self);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -237,9 +237,10 @@ lumiera_mmap_delete (LumieraMMap self)
|
|||
/* The matching mappings->lock must be hold or being unrelevant (mappings destructor) here, we can't asset this from here, good luck */
|
||||
llist_unlink (&self->searchnode);
|
||||
|
||||
TRACE (mmap, "unmap at %p with size %zd", self->address, self->size);
|
||||
munmap (self->address, self->size);
|
||||
free (self->refmap);
|
||||
free (self);
|
||||
lumiera_free (self->refmap);
|
||||
lumiera_free (self);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +257,7 @@ lumiera_mmap_destroy_node (LList node)
|
|||
llist_unlink (&self->searchnode); TODO ("must lock mmapings -> deadlock");
|
||||
|
||||
munmap (self->address, self->size);
|
||||
free (self->refmap);
|
||||
lumiera_free (self->refmap);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ typedef struct lumiera_mmap_struct lumiera_mmap;
|
|||
typedef lumiera_mmap* LumieraMMap;
|
||||
|
||||
|
||||
#include "backend/file.h"
|
||||
#include "backend/filedescriptor.h"
|
||||
|
||||
|
||||
|
|
@ -61,17 +62,27 @@ struct lumiera_mmap_struct
|
|||
size_t size;
|
||||
void* address;
|
||||
|
||||
/** accumulated references, this is 0 when checked into the cache **/
|
||||
unsigned long refcnt;
|
||||
|
||||
/** array with refcounters per chunk **/
|
||||
unsigned short* refmap;
|
||||
unsigned short* refmap; // TODO flexible array?
|
||||
};
|
||||
|
||||
|
||||
LumieraMMap
|
||||
lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t start, size_t size, size_t chunksize);
|
||||
lumiera_mmap_init (LumieraMMap self, LumieraFile file, off_t start, size_t size);
|
||||
|
||||
|
||||
LumieraMMap
|
||||
lumiera_mmap_new (LumieraFile file, LList acquirer, off_t start, size_t size, size_t chunksize);
|
||||
lumiera_mmap_new (LumieraFile file, off_t start, size_t size);
|
||||
|
||||
|
||||
static inline void*
|
||||
lumiera_mmap_address (LumieraMMap self)
|
||||
{
|
||||
return self->address;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ lumiera_mmapcache_checkout (LumieraMMapcache self, LumieraMMap handle)
|
|||
{
|
||||
TODO ("cached stats");
|
||||
lumiera_mrucache_checkout (&self->cache, &handle->cachenode);
|
||||
++handle->refcnt;
|
||||
}
|
||||
|
||||
return handle;
|
||||
|
|
@ -152,6 +153,7 @@ lumiera_mmapcache_checkin (LumieraMMapcache self, LumieraMMap handle)
|
|||
LUMIERA_MUTEX_SECTION (mmapcache, &self->lock)
|
||||
{
|
||||
TODO ("cached stats");
|
||||
--handle->refcnt;
|
||||
lumiera_mrucache_checkin (&self->cache, &handle->cachenode);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,9 +95,11 @@ lumiera_mmapings_mmap_acquire (LumieraMMapings self, LumieraFile file, LList acq
|
|||
{
|
||||
REQUIRE (llist_is_empty (acquirer));
|
||||
|
||||
/* find best matching mmap, crude way */
|
||||
/* find first matching mmap, crude way */
|
||||
LLIST_FOREACH (&self->mmaps, node)
|
||||
{
|
||||
TODO ("improve this selection algorithm, choose mmaps by size, move mfu to head etc");
|
||||
|
||||
LumieraMMap mmap = LLIST_TO_STRUCTP (node, lumiera_mmap, searchnode);
|
||||
|
||||
if (mmap->size >= size && mmap->start <= start && mmap->start+mmap->size >= start+size)
|
||||
|
|
@ -107,24 +109,25 @@ lumiera_mmapings_mmap_acquire (LumieraMMapings self, LumieraFile file, LList acq
|
|||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
/* found? */
|
||||
if (ret)
|
||||
{
|
||||
/* create new mmap */
|
||||
TRACE (mmapings, "mmap not found, creating", mmap);
|
||||
ret = lumiera_mmap_new (file, acquirer, start, size, self->chunksize);
|
||||
|
||||
llist_insert_head (&self->mmaps, &ret->searchnode);
|
||||
|
||||
TODO ("sort search list");
|
||||
if (!ret->refcnt)
|
||||
/* in cache, needs to me checked out */
|
||||
lumiera_mmapcache_checkout (lumiera_mcache, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* found mmap */
|
||||
/* create new mmap */
|
||||
TRACE (mmapings, "mmap not found, creating", mmap);
|
||||
ret = lumiera_mmap_new (file, start, size);
|
||||
|
||||
UNIMPLEMENTED ("reuse existing mmap");
|
||||
//lumiera_mmapcache_checkout (lumiera_mcache, self);
|
||||
// checkout add acquirer
|
||||
llist_insert_head (&self->mmaps, &ret->searchnode);
|
||||
|
||||
TODO ("sort search list?");
|
||||
}
|
||||
|
||||
llist_insert_head (&ret->cachenode, acquirer);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ typedef lumiera_mmapings* LumieraMMapings;
|
|||
|
||||
#include "backend/filedescriptor.h"
|
||||
#include "backend/mmap.h"
|
||||
#include "backend/file.h"
|
||||
|
||||
#include <nobug.h>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue