1515
1616#}END utilities
1717
18- class SlidingCursor (object ):
18+ class MemoryCursor (object ):
1919 """Pointer into the mapped region of the memory manager, keeping the current window
2020 alive until it is destroyed.
2121
@@ -28,11 +28,6 @@ class SlidingCursor(object):
2828 '_size' # maximum size we should provide
2929 )
3030
31- #{ Configuration
32- MapWindowCls = MapWindow
33- MapRegionCls = MapRegion
34- #} END configuration
35-
3631 def __init__ (self , manager = None , regions = None ):
3732 self ._manager = manager
3833 self ._rlist = regions
@@ -82,7 +77,7 @@ def assign(self, rhs):
8277 self ._destroy ()
8378 self ._copy_from (rhs )
8479
85- def use_region (self , offset , size , flags = 0 , _is_recursive = False ):
80+ def use_region (self , offset , size , flags = 0 ):
8681 """Assure we point to a window which allows access to the given offset into the file
8782 :param offset: absolute offset in bytes into the file
8883 :param size: amount of bytes to map
@@ -104,115 +99,14 @@ def use_region(self, offset, size, flags = 0, _is_recursive=False):
10499 # END handle existing region
105100 # END check existing region
106101
102+ # offset too large ?
103+ if offset >= self ._rlist .file_size ():
104+ return self
105+ #END handle offset
106+
107107 if need_region :
108- window_size = man ._window_size
109-
110- # abort on offsets beyond our mapped file's size - currently we are invalid
111- if offset >= self .file_size ():
112- return self
113- # END handle offset too large
114-
115- # bisect to find an existing region. The c++ implementation cannot
116- # do that as it uses a linked list for regions.
117- existing_region = None
118- a = self ._rlist
119- lo = 0
120- hi = len (a )
121- while lo < hi :
122- mid = (lo + hi )// 2
123- ofs = a [mid ]._b
124- if ofs <= offset :
125- if a [mid ].includes_ofs (offset ):
126- existing_region = a [mid ]
127- break
128- #END have region
129- lo = mid + 1
130- else :
131- hi = mid
132- #END handle position
133- #END while bisecting
134-
135- if existing_region is None :
136- left = self .MapWindowCls (0 , 0 )
137- mid = self .MapWindowCls (offset , size )
138- right = self .MapWindowCls (self .file_size (), 0 )
139-
140- # we want to honor the max memory size, and assure we have anough
141- # memory available
142- # Save calls !
143- if self ._manager ._memory_size + window_size > self ._manager ._max_memory_size :
144- man ._collect_lru_region (window_size )
145- #END handle collection
146-
147- # we assume the list remains sorted by offset
148- insert_pos = 0
149- len_regions = len (a )
150- if len_regions == 1 :
151- if a [0 ]._b <= offset :
152- insert_pos = 1
153- #END maintain sort
154- else :
155- # find insert position
156- insert_pos = len_regions
157- for i , region in enumerate (a ):
158- if region ._b > offset :
159- insert_pos = i
160- break
161- #END if insert position is correct
162- #END for each region
163- # END obtain insert pos
164-
165- # adjust the actual offset and size values to create the largest
166- # possible mapping
167- if insert_pos == 0 :
168- if len_regions :
169- right = self .MapWindowCls .from_region (a [insert_pos ])
170- #END adjust right side
171- else :
172- if insert_pos != len_regions :
173- right = self .MapWindowCls .from_region (a [insert_pos ])
174- # END adjust right window
175- left = self .MapWindowCls .from_region (a [insert_pos - 1 ])
176- #END adjust surrounding windows
177-
178- mid .extend_left_to (left , window_size )
179- mid .extend_right_to (right , window_size )
180- mid .align ()
181-
182- # it can happen that we align beyond the end of the file
183- if mid .ofs_end () > right .ofs :
184- mid .size = right .ofs - mid .ofs
185- #END readjust size
186-
187- # insert new region at the right offset to keep the order
188- try :
189- if man ._handle_count >= man ._max_handle_count :
190- raise Exception
191- #END assert own imposed max file handles
192- self ._region = self .MapRegionCls (a .path_or_fd (), mid .ofs , mid .size , flags )
193- except Exception :
194- # apparently we are out of system resources or hit a limit
195- # As many more operations are likely to fail in that condition (
196- # like reading a file from disk, etc) we free up as much as possible
197- # As this invalidates our insert position, we have to recurse here
198- # NOTE: The c++ version uses a linked list to curcumvent this, but
199- # using that in python is probably too slow anyway
200- if _is_recursive :
201- # we already tried this, and still have no success in obtaining
202- # a mapping. This is an exception, so we propagate it
203- raise
204- #END handle existing recursion
205- man ._collect_lru_region (0 )
206- return self .use_region (offset , size , flags , True )
207- #END handle exceptions
208-
209- man ._handle_count += 1
210- man ._memory_size += self ._region .size ()
211- a .insert (insert_pos , self ._region )
212- else :
213- self ._region = existing_region
214- #END need region handling
215- #END handle acquire region
108+ self ._region = man ._obtain_region (self ._rlist , offset , size , flags , False )
109+ #END need region handling
216110
217111 self ._region .increment_usage_count ()
218112 self ._ofs = offset - self ._region ._b
@@ -301,6 +195,7 @@ def fd(self):
301195 #} END interface
302196
303197
198+
304199class SlidingWindowMapManager (object ):
305200 """Maintains a list of ranges of mapped memory regions in one or more files and allows to easily
306201 obtain additional regions assuring there is no overlap.
@@ -325,6 +220,8 @@ class SlidingWindowMapManager(object):
325220
326221 #{ Configuration
327222 MapRegionListCls = MapRegionList
223+ MapWindowCls = MapWindow
224+ MapRegionCls = MapRegion
328225 #} END configuration
329226
330227 _MB_in_bytes = 1024 * 1024
@@ -398,6 +295,111 @@ def _collect_lru_region(self, size):
398295
399296 return num_found
400297
298+ def _obtain_region (self , a , offset , size , flags , is_recursive ):
299+ """Utilty to create a new region - for more information on the parameters,
300+ see MapCursor.use_region.
301+ :param a: A regions (a)rray
302+ :return: The newly created region"""
303+ # bisect to find an existing region. The c++ implementation cannot
304+ # do that as it uses a linked list for regions.
305+ r = None
306+ lo = 0
307+ hi = len (a )
308+ while lo < hi :
309+ mid = (lo + hi )// 2
310+ ofs = a [mid ]._b
311+ if ofs <= offset :
312+ if a [mid ].includes_ofs (offset ):
313+ r = a [mid ]
314+ break
315+ #END have region
316+ lo = mid + 1
317+ else :
318+ hi = mid
319+ #END handle position
320+ #END while bisecting
321+
322+ if r is None :
323+ window_size = self ._window_size
324+ left = self .MapWindowCls (0 , 0 )
325+ mid = self .MapWindowCls (offset , size )
326+ right = self .MapWindowCls (a .file_size (), 0 )
327+
328+ # we want to honor the max memory size, and assure we have anough
329+ # memory available
330+ # Save calls !
331+ if self ._memory_size + window_size > self ._max_memory_size :
332+ self ._collect_lru_region (window_size )
333+ #END handle collection
334+
335+ # we assume the list remains sorted by offset
336+ insert_pos = 0
337+ len_regions = len (a )
338+ if len_regions == 1 :
339+ if a [0 ]._b <= offset :
340+ insert_pos = 1
341+ #END maintain sort
342+ else :
343+ # find insert position
344+ insert_pos = len_regions
345+ for i , region in enumerate (a ):
346+ if region ._b > offset :
347+ insert_pos = i
348+ break
349+ #END if insert position is correct
350+ #END for each region
351+ # END obtain insert pos
352+
353+ # adjust the actual offset and size values to create the largest
354+ # possible mapping
355+ if insert_pos == 0 :
356+ if len_regions :
357+ right = self .MapWindowCls .from_region (a [insert_pos ])
358+ #END adjust right side
359+ else :
360+ if insert_pos != len_regions :
361+ right = self .MapWindowCls .from_region (a [insert_pos ])
362+ # END adjust right window
363+ left = self .MapWindowCls .from_region (a [insert_pos - 1 ])
364+ #END adjust surrounding windows
365+
366+ mid .extend_left_to (left , window_size )
367+ mid .extend_right_to (right , window_size )
368+ mid .align ()
369+
370+ # it can happen that we align beyond the end of the file
371+ if mid .ofs_end () > right .ofs :
372+ mid .size = right .ofs - mid .ofs
373+ #END readjust size
374+
375+ # insert new region at the right offset to keep the order
376+ try :
377+ if self ._handle_count >= self ._max_handle_count :
378+ raise Exception
379+ #END assert own imposed max file handles
380+ r = self .MapRegionCls (a .path_or_fd (), mid .ofs , mid .size , flags )
381+ except Exception :
382+ # apparently we are out of system resources or hit a limit
383+ # As many more operations are likely to fail in that condition (
384+ # like reading a file from disk, etc) we free up as much as possible
385+ # As this invalidates our insert position, we have to recurse here
386+ # NOTE: The c++ version uses a linked list to curcumvent this, but
387+ # using that in python is probably too slow anyway
388+ if is_recursive :
389+ # we already tried this, and still have no success in obtaining
390+ # a mapping. This is an exception, so we propagate it
391+ raise
392+ #END handle existing recursion
393+ self ._collect_lru_region (0 )
394+ return self ._obtain_region (a , offset , size , flags , True )
395+ #END handle exceptions
396+
397+ self ._handle_count += 1
398+ self ._memory_size += r .size ()
399+ a .insert (insert_pos , r )
400+ # END create new region
401+ return r
402+
401403 #{ Interface
402404 def make_cursor (self , path_or_fd ):
403405 """:return: a cursor pointing to the given path or file descriptor.
@@ -414,7 +416,7 @@ def make_cursor(self, path_or_fd):
414416 regions = self .MapRegionListCls (path_or_fd )
415417 self ._fdict [path_or_fd ] = regions
416418 # END obtain region for path
417- return SlidingCursor (self , regions )
419+ return MemoryCursor (self , regions )
418420
419421 def collect (self ):
420422 """Collect all available free-to-collect mapped regions
0 commit comments