diff options
| author | Sebastian Thiel <byronimo@gmail.com> | 2011-06-10 15:31:07 +0200 |
|---|---|---|
| committer | Sebastian Thiel <byronimo@gmail.com> | 2011-06-10 15:31:07 +0200 |
| commit | bc78951823623f9a529d0b515d85d6a0a1a1d8ac (patch) | |
| tree | cad341815c19682f7353e4ebde6f04f258918dc0 /smmap | |
| parent | 9dc4a8dd154d15a243cd2d54f7d1631a913106f0 (diff) | |
| download | smmap-bc78951823623f9a529d0b515d85d6a0a1a1d8ac.tar.gz | |
moved code from cursor into manager, as it belongs there. This is a design error inherited from c++, but actually it makes overrides a bit harder, or lets say, less native, as the sliding mechanics where implemented in a class which is just the handle to a memory map in the end, which doesn't have to care about its allocation
Diffstat (limited to 'smmap')
| -rw-r--r-- | smmap/buf.py | 2 | ||||
| -rw-r--r-- | smmap/mman.py | 234 | ||||
| -rw-r--r-- | smmap/test/test_mman.py | 6 |
3 files changed, 122 insertions, 120 deletions
diff --git a/smmap/buf.py b/smmap/buf.py index 94650a5..7414503 100644 --- a/smmap/buf.py +++ b/smmap/buf.py @@ -1,5 +1,5 @@ """Module with a simple buffer implementation using the memory manager""" -from mman import SlidingCursor +from mman import MemoryCursor import sys diff --git a/smmap/mman.py b/smmap/mman.py index 3126122..16f8781 100644 --- a/smmap/mman.py +++ b/smmap/mman.py @@ -15,7 +15,7 @@ __all__ = ["SlidingWindowMapManager"] #}END utilities -class SlidingCursor(object): +class MemoryCursor(object): """Pointer into the mapped region of the memory manager, keeping the current window alive until it is destroyed. @@ -28,11 +28,6 @@ class SlidingCursor(object): '_size' # maximum size we should provide ) - #{ Configuration - MapWindowCls = MapWindow - MapRegionCls = MapRegion - #} END configuration - def __init__(self, manager = None, regions = None): self._manager = manager self._rlist = regions @@ -82,7 +77,7 @@ class SlidingCursor(object): self._destroy() self._copy_from(rhs) - def use_region(self, offset, size, flags = 0, _is_recursive=False): + def use_region(self, offset, size, flags = 0): """Assure we point to a window which allows access to the given offset into the file :param offset: absolute offset in bytes into the file :param size: amount of bytes to map @@ -104,115 +99,14 @@ class SlidingCursor(object): # END handle existing region # END check existing region + # offset too large ? + if offset >= self._rlist.file_size(): + return self + #END handle offset + if need_region: - window_size = man._window_size - - # abort on offsets beyond our mapped file's size - currently we are invalid - if offset >= self.file_size(): - return self - # END handle offset too large - - # bisect to find an existing region. The c++ implementation cannot - # do that as it uses a linked list for regions. - existing_region = None - a = self._rlist - lo = 0 - hi = len(a) - while lo < hi: - mid = (lo+hi)//2 - ofs = a[mid]._b - if ofs <= offset: - if a[mid].includes_ofs(offset): - existing_region = a[mid] - break - #END have region - lo = mid+1 - else: - hi = mid - #END handle position - #END while bisecting - - if existing_region is None: - left = self.MapWindowCls(0, 0) - mid = self.MapWindowCls(offset, size) - right = self.MapWindowCls(self.file_size(), 0) - - # we want to honor the max memory size, and assure we have anough - # memory available - # Save calls ! - if self._manager._memory_size + window_size > self._manager._max_memory_size: - man._collect_lru_region(window_size) - #END handle collection - - # we assume the list remains sorted by offset - insert_pos = 0 - len_regions = len(a) - if len_regions == 1: - if a[0]._b <= offset: - insert_pos = 1 - #END maintain sort - else: - # find insert position - insert_pos = len_regions - for i, region in enumerate(a): - if region._b > offset: - insert_pos = i - break - #END if insert position is correct - #END for each region - # END obtain insert pos - - # adjust the actual offset and size values to create the largest - # possible mapping - if insert_pos == 0: - if len_regions: - right = self.MapWindowCls.from_region(a[insert_pos]) - #END adjust right side - else: - if insert_pos != len_regions: - right = self.MapWindowCls.from_region(a[insert_pos]) - # END adjust right window - left = self.MapWindowCls.from_region(a[insert_pos - 1]) - #END adjust surrounding windows - - mid.extend_left_to(left, window_size) - mid.extend_right_to(right, window_size) - mid.align() - - # it can happen that we align beyond the end of the file - if mid.ofs_end() > right.ofs: - mid.size = right.ofs - mid.ofs - #END readjust size - - # insert new region at the right offset to keep the order - try: - if man._handle_count >= man._max_handle_count: - raise Exception - #END assert own imposed max file handles - self._region = self.MapRegionCls(a.path_or_fd(), mid.ofs, mid.size, flags) - except Exception: - # apparently we are out of system resources or hit a limit - # As many more operations are likely to fail in that condition ( - # like reading a file from disk, etc) we free up as much as possible - # As this invalidates our insert position, we have to recurse here - # NOTE: The c++ version uses a linked list to curcumvent this, but - # using that in python is probably too slow anyway - if _is_recursive: - # we already tried this, and still have no success in obtaining - # a mapping. This is an exception, so we propagate it - raise - #END handle existing recursion - man._collect_lru_region(0) - return self.use_region(offset, size, flags, True) - #END handle exceptions - - man._handle_count += 1 - man._memory_size += self._region.size() - a.insert(insert_pos, self._region) - else: - self._region = existing_region - #END need region handling - #END handle acquire region + self._region = man._obtain_region(self._rlist, offset, size, flags, False) + #END need region handling self._region.increment_usage_count() self._ofs = offset - self._region._b @@ -301,6 +195,7 @@ class SlidingCursor(object): #} END interface + class SlidingWindowMapManager(object): """Maintains a list of ranges of mapped memory regions in one or more files and allows to easily obtain additional regions assuring there is no overlap. @@ -325,6 +220,8 @@ class SlidingWindowMapManager(object): #{ Configuration MapRegionListCls = MapRegionList + MapWindowCls = MapWindow + MapRegionCls = MapRegion #} END configuration _MB_in_bytes = 1024 * 1024 @@ -398,6 +295,111 @@ class SlidingWindowMapManager(object): return num_found + def _obtain_region(self, a, offset, size, flags, is_recursive): + """Utilty to create a new region - for more information on the parameters, + see MapCursor.use_region. + :param a: A regions (a)rray + :return: The newly created region""" + # bisect to find an existing region. The c++ implementation cannot + # do that as it uses a linked list for regions. + r = None + lo = 0 + hi = len(a) + while lo < hi: + mid = (lo+hi)//2 + ofs = a[mid]._b + if ofs <= offset: + if a[mid].includes_ofs(offset): + r = a[mid] + break + #END have region + lo = mid+1 + else: + hi = mid + #END handle position + #END while bisecting + + if r is None: + window_size = self._window_size + left = self.MapWindowCls(0, 0) + mid = self.MapWindowCls(offset, size) + right = self.MapWindowCls(a.file_size(), 0) + + # we want to honor the max memory size, and assure we have anough + # memory available + # Save calls ! + if self._memory_size + window_size > self._max_memory_size: + self._collect_lru_region(window_size) + #END handle collection + + # we assume the list remains sorted by offset + insert_pos = 0 + len_regions = len(a) + if len_regions == 1: + if a[0]._b <= offset: + insert_pos = 1 + #END maintain sort + else: + # find insert position + insert_pos = len_regions + for i, region in enumerate(a): + if region._b > offset: + insert_pos = i + break + #END if insert position is correct + #END for each region + # END obtain insert pos + + # adjust the actual offset and size values to create the largest + # possible mapping + if insert_pos == 0: + if len_regions: + right = self.MapWindowCls.from_region(a[insert_pos]) + #END adjust right side + else: + if insert_pos != len_regions: + right = self.MapWindowCls.from_region(a[insert_pos]) + # END adjust right window + left = self.MapWindowCls.from_region(a[insert_pos - 1]) + #END adjust surrounding windows + + mid.extend_left_to(left, window_size) + mid.extend_right_to(right, window_size) + mid.align() + + # it can happen that we align beyond the end of the file + if mid.ofs_end() > right.ofs: + mid.size = right.ofs - mid.ofs + #END readjust size + + # insert new region at the right offset to keep the order + try: + if self._handle_count >= self._max_handle_count: + raise Exception + #END assert own imposed max file handles + r = self.MapRegionCls(a.path_or_fd(), mid.ofs, mid.size, flags) + except Exception: + # apparently we are out of system resources or hit a limit + # As many more operations are likely to fail in that condition ( + # like reading a file from disk, etc) we free up as much as possible + # As this invalidates our insert position, we have to recurse here + # NOTE: The c++ version uses a linked list to curcumvent this, but + # using that in python is probably too slow anyway + if is_recursive: + # we already tried this, and still have no success in obtaining + # a mapping. This is an exception, so we propagate it + raise + #END handle existing recursion + self._collect_lru_region(0) + return self._obtain_region(a, offset, size, flags, True) + #END handle exceptions + + self._handle_count += 1 + self._memory_size += r.size() + a.insert(insert_pos, r) + # END create new region + return r + #{ Interface def make_cursor(self, path_or_fd): """:return: a cursor pointing to the given path or file descriptor. @@ -414,7 +416,7 @@ class SlidingWindowMapManager(object): regions = self.MapRegionListCls(path_or_fd) self._fdict[path_or_fd] = regions # END obtain region for path - return SlidingCursor(self, regions) + return MemoryCursor(self, regions) def collect(self): """Collect all available free-to-collect mapped regions diff --git a/smmap/test/test_mman.py b/smmap/test/test_mman.py index dfe43e7..79c6f98 100644 --- a/smmap/test/test_mman.py +++ b/smmap/test/test_mman.py @@ -1,7 +1,7 @@ from lib import TestBase, FileCreator from smmap.mman import * -from smmap.mman import SlidingCursor +from smmap.mman import MemoryCursor from smmap.util import align_to_mmap from smmap.exc import RegionCollectionError @@ -17,7 +17,7 @@ class TestMMan(TestBase): fc = FileCreator(self.k_window_test_size, "cursor_test") man = SlidingWindowMapManager() - ci = SlidingCursor(man) # invalid cursor + ci = MemoryCursor(man) # invalid cursor assert not ci.is_valid() assert not ci.is_associated() assert ci.size() == 0 # this is cached, so we can query it in invalid state @@ -43,7 +43,7 @@ class TestMMan(TestBase): # destruction is fine (even multiple times) cv._destroy() - SlidingCursor(man)._destroy() + MemoryCursor(man)._destroy() def test_memory_manager(self): man = SlidingWindowMapManager() |
