summaryrefslogtreecommitdiff
path: root/smmap
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2011-06-08 20:26:51 +0200
committerSebastian Thiel <byronimo@gmail.com>2011-06-08 20:26:51 +0200
commit66a78db0127ed84e22cda5aed2009955765959e4 (patch)
tree17f38d6831e8eb5e25fd14577e660e01a78eac3d /smmap
parent2156e9ab02ea27289e6b26c11b024685b3816935 (diff)
downloadsmmap-66a78db0127ed84e22cda5aed2009955765959e4.tar.gz
Implemented MappedRegion type including test
Diffstat (limited to 'smmap')
-rw-r--r--smmap/mman.py73
-rw-r--r--smmap/test/test_mman.py23
2 files changed, 87 insertions, 9 deletions
diff --git a/smmap/mman.py b/smmap/mman.py
index 004987a..c5a3887 100644
--- a/smmap/mman.py
+++ b/smmap/mman.py
@@ -3,6 +3,7 @@
__all__ = ["MappedMemoryManager"]
import os
+import sys
import mmap
from mmap import PAGESIZE
@@ -64,16 +65,22 @@ class Window(object):
self.size = min(self.size + (window.ofs - self.ofs_end()), max_size)
-class Region(object):
+class MappedRegion(object):
"""Defines a mapped region of memory, aligned to pagesizes
:note: deallocates used region automatically on destruction"""
- __slots__ = (
+ __slots__ = [
'_b' , # beginning of mapping
'_mf', # mapped memory chunk (as returned by mmap)
'_nc', # number of clients using this region
- '_uc' # total amount of usages
- )
+ '_uc', # total amount of usages
+ '_ms' # actual size of the mapping
+ ]
+ _need_compat_layer = sys.version_info[1] < 6
+ if _need_compat_layer:
+ __slots__.append('_mfb') # mapped memory buffer to provide offset
+ #END handle additional slot
+
def __init__(self, path, ofs, size):
"""Initialize a region, allocate the memory map
@@ -88,10 +95,66 @@ class Region(object):
fd = os.open(path, os.O_RDONLY|getattr(os, 'O_BINARY', 0))
try:
- self._mf = mmap.mmap(fd, size, access=mmap.ACCESS_READ, offset=ofs)
+ kwargs = dict(access=mmap.ACCESS_READ, offset=ofs)
+ corrected_size = size
+ if self._need_compat_layer:
+ del(kwargs['offset'])
+ corrected_size += ofs
+ # END handle python not supporting offset ! Arg
+
+ # have to correct size, otherwise (instead of the c version) it will
+ # bark that the size is too large ... many extra file accesses because
+ # if this ... argh !
+ self._mf = mmap.mmap(fd, min(os.fstat(fd).st_size, corrected_size), **kwargs)
+
+ print len(self._mf)
+ if self._need_compat_layer:
+ self._mfb = buffer(self._mf, ofs, size)
+ #END handle buffer wrapping
finally:
os.close(fd)
#END close file handle
+
+ def ofs_begin(self):
+ """:return: absolute byte offset to the first byte of the mapping"""
+ return self._b
+
+ def size(self):
+ """:return: total size of the mapped region in bytes"""
+ return len(self._mf)
+
+ def ofs_end(self):
+ """:return: Absolute offset to one byte beyond the mapping into the file"""
+ return self._b + self.size()
+
+ def includes_ofs(self, ofs):
+ """:return: True if the given offset can be read in our mapped region"""
+ return (ofs >= self.ofs_begin()) and (ofs <= self.ofs_end())
+
+ def client_count(self):
+ """:return: number of clients currently using this region"""
+ return self._nc
+
+ def adjust_client_count(self, ofs):
+ """Adjust the client count by the given positive or negative offset"""
+ self._nc += ofs
+
+ def usage_count(self):
+ """:return: amount of usages so far"""
+ return self._uc
+
+ def adjust_usage_count(self, ofs):
+ """Adjust the usage count by the given positive or negative offset"""
+ self._uc += ofs
+
+ # re-define all methods which need offset adjustments in compatibility mode
+ if _need_compat_layer:
+ def size(self):
+ return len(self._mf) - self._b
+
+ def ofs_end(self):
+ return len(self._mf)
+ #END handle compat layer
class MappedMemoryManager(object):
diff --git a/smmap/test/test_mman.py b/smmap/test/test_mman.py
index faee8c9..482ef92 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 Region
+from smmap.mman import MappedRegion
from smmap.mman import Window
import sys
@@ -59,12 +59,27 @@ class TestMMan(TestBase):
def test_region(self):
fc = FileCreator(self._window_test_size, "window_test")
- rfull = Region(fc.path, 0, fc.size)
+ half_size = fc.size / 2
+ rofs = 4000
+ rfull = MappedRegion(fc.path, 0, fc.size)
+ rhalfofs = MappedRegion(fc.path, rofs, fc.size)
+ rhalfsize = MappedRegion(fc.path, 0, half_size)
+ # offsets
+ assert rfull.ofs_begin() == 0 and rfull.size() == fc.size
+ assert rfull.ofs_end() == fc.size # if this method works, it works always
+ assert rhalfofs.ofs_begin() == rofs and rhalfofs.size() == fc.size - rofs
+ assert rhalfsize.ofs_begin() == 0 and rhalfsize.size() == half_size
+
+ assert rfull.includes_ofs(0) and rfull.includes_ofs(fc.size-1) and rfull.includes_ofs(half_size)
+ assert not rfull.includes_ofs(-1) and not rfull.includes_ofs(sys.maxint)
+ assert rhalfofs.includes_ofs(rofs) and not rhalfofs.includes_ofs(0)
+
+ # window constructor
+ w = Window.from_region(rfull)
+ assert w.ofs == rfull.ofs_begin() and w.ofs_end() == rfull.ofs_end()
- Window.from_region # todo
- pass
def test_basics(self):
pass