Skip to content

Commit 66a78db

Browse files
committed
Implemented MappedRegion type including test
1 parent 2156e9a commit 66a78db

2 files changed

Lines changed: 87 additions & 9 deletions

File tree

smmap/mman.py

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
__all__ = ["MappedMemoryManager"]
44

55
import os
6+
import sys
67
import mmap
78

89
from mmap import PAGESIZE
@@ -64,16 +65,22 @@ def extend_right_to(self, window, max_size):
6465
self.size = min(self.size + (window.ofs - self.ofs_end()), max_size)
6566

6667

67-
class Region(object):
68+
class MappedRegion(object):
6869
"""Defines a mapped region of memory, aligned to pagesizes
6970
:note: deallocates used region automatically on destruction"""
70-
__slots__ = (
71+
__slots__ = [
7172
'_b' , # beginning of mapping
7273
'_mf', # mapped memory chunk (as returned by mmap)
7374
'_nc', # number of clients using this region
74-
'_uc' # total amount of usages
75-
)
75+
'_uc', # total amount of usages
76+
'_ms' # actual size of the mapping
77+
]
78+
_need_compat_layer = sys.version_info[1] < 6
7679

80+
if _need_compat_layer:
81+
__slots__.append('_mfb') # mapped memory buffer to provide offset
82+
#END handle additional slot
83+
7784

7885
def __init__(self, path, ofs, size):
7986
"""Initialize a region, allocate the memory map
@@ -88,10 +95,66 @@ def __init__(self, path, ofs, size):
8895

8996
fd = os.open(path, os.O_RDONLY|getattr(os, 'O_BINARY', 0))
9097
try:
91-
self._mf = mmap.mmap(fd, size, access=mmap.ACCESS_READ, offset=ofs)
98+
kwargs = dict(access=mmap.ACCESS_READ, offset=ofs)
99+
corrected_size = size
100+
if self._need_compat_layer:
101+
del(kwargs['offset'])
102+
corrected_size += ofs
103+
# END handle python not supporting offset ! Arg
104+
105+
# have to correct size, otherwise (instead of the c version) it will
106+
# bark that the size is too large ... many extra file accesses because
107+
# if this ... argh !
108+
self._mf = mmap.mmap(fd, min(os.fstat(fd).st_size, corrected_size), **kwargs)
109+
110+
print len(self._mf)
111+
if self._need_compat_layer:
112+
self._mfb = buffer(self._mf, ofs, size)
113+
#END handle buffer wrapping
92114
finally:
93115
os.close(fd)
94116
#END close file handle
117+
118+
def ofs_begin(self):
119+
""":return: absolute byte offset to the first byte of the mapping"""
120+
return self._b
121+
122+
def size(self):
123+
""":return: total size of the mapped region in bytes"""
124+
return len(self._mf)
125+
126+
def ofs_end(self):
127+
""":return: Absolute offset to one byte beyond the mapping into the file"""
128+
return self._b + self.size()
129+
130+
def includes_ofs(self, ofs):
131+
""":return: True if the given offset can be read in our mapped region"""
132+
return (ofs >= self.ofs_begin()) and (ofs <= self.ofs_end())
133+
134+
def client_count(self):
135+
""":return: number of clients currently using this region"""
136+
return self._nc
137+
138+
def adjust_client_count(self, ofs):
139+
"""Adjust the client count by the given positive or negative offset"""
140+
self._nc += ofs
141+
142+
def usage_count(self):
143+
""":return: amount of usages so far"""
144+
return self._uc
145+
146+
def adjust_usage_count(self, ofs):
147+
"""Adjust the usage count by the given positive or negative offset"""
148+
self._uc += ofs
149+
150+
# re-define all methods which need offset adjustments in compatibility mode
151+
if _need_compat_layer:
152+
def size(self):
153+
return len(self._mf) - self._b
154+
155+
def ofs_end(self):
156+
return len(self._mf)
157+
#END handle compat layer
95158

96159

97160
class MappedMemoryManager(object):

smmap/test/test_mman.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from lib import TestBase, FileCreator
22

33
from smmap.mman import *
4-
from smmap.mman import Region
4+
from smmap.mman import MappedRegion
55
from smmap.mman import Window
66

77
import sys
@@ -59,12 +59,27 @@ def test_window(self):
5959

6060
def test_region(self):
6161
fc = FileCreator(self._window_test_size, "window_test")
62-
rfull = Region(fc.path, 0, fc.size)
62+
half_size = fc.size / 2
63+
rofs = 4000
64+
rfull = MappedRegion(fc.path, 0, fc.size)
65+
rhalfofs = MappedRegion(fc.path, rofs, fc.size)
66+
rhalfsize = MappedRegion(fc.path, 0, half_size)
6367

68+
# offsets
69+
assert rfull.ofs_begin() == 0 and rfull.size() == fc.size
70+
assert rfull.ofs_end() == fc.size # if this method works, it works always
6471

72+
assert rhalfofs.ofs_begin() == rofs and rhalfofs.size() == fc.size - rofs
73+
assert rhalfsize.ofs_begin() == 0 and rhalfsize.size() == half_size
74+
75+
assert rfull.includes_ofs(0) and rfull.includes_ofs(fc.size-1) and rfull.includes_ofs(half_size)
76+
assert not rfull.includes_ofs(-1) and not rfull.includes_ofs(sys.maxint)
77+
assert rhalfofs.includes_ofs(rofs) and not rhalfofs.includes_ofs(0)
78+
79+
# window constructor
80+
w = Window.from_region(rfull)
81+
assert w.ofs == rfull.ofs_begin() and w.ofs_end() == rfull.ofs_end()
6582

66-
Window.from_region # todo
67-
pass
6883

6984
def test_basics(self):
7085
pass

0 commit comments

Comments
 (0)