From db202e298e2e5e7a53972add793516e31906accb Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 8 Dec 2008 20:57:57 +0100 Subject: [PATCH] mmap updates/refactoring --- src/backend/mmap.c | 87 +++++++++++++++++++++-------------------- src/backend/mmap.h | 17 ++++++-- src/backend/mmapcache.c | 2 + src/backend/mmapings.c | 29 ++++++++------ src/backend/mmapings.h | 1 + 5 files changed, 77 insertions(+), 59 deletions(-) diff --git a/src/backend/mmap.c b/src/backend/mmap.c index 6ecf531a2..4cccc8741 100644 --- a/src/backend/mmap.c +++ b/src/backend/mmap.c @@ -27,6 +27,7 @@ #include #include +#include /** * @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; } diff --git a/src/backend/mmap.h b/src/backend/mmap.h index 73e1fc07c..90e2006a2 100644 --- a/src/backend/mmap.h +++ b/src/backend/mmap.h @@ -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 diff --git a/src/backend/mmapcache.c b/src/backend/mmapcache.c index 05fe08e19..e7ca62db2 100644 --- a/src/backend/mmapcache.c +++ b/src/backend/mmapcache.c @@ -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); } } diff --git a/src/backend/mmapings.c b/src/backend/mmapings.c index 3193b67a9..b36d77d62 100644 --- a/src/backend/mmapings.c +++ b/src/backend/mmapings.c @@ -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; diff --git a/src/backend/mmapings.h b/src/backend/mmapings.h index 77bfbffad..17548f1a9 100644 --- a/src/backend/mmapings.h +++ b/src/backend/mmapings.h @@ -30,6 +30,7 @@ typedef lumiera_mmapings* LumieraMMapings; #include "backend/filedescriptor.h" #include "backend/mmap.h" +#include "backend/file.h" #include