1
2
3
4
5 from __future__ import division
6 from builtins import object
7 import logging
8
9 _logger = logging.getLogger('arvados.ranges')
10
11
12 RANGES_SPAM = 9
13
15 __slots__ = ("locator", "range_start", "range_size", "segment_offset")
16
17 - def __init__(self, locator, range_start, range_size, segment_offset=0):
18 self.locator = locator
19 self.range_start = range_start
20 self.range_size = range_size
21 self.segment_offset = segment_offset
22
24 return "Range(%r, %r, %r, %r)" % (self.locator, self.range_start, self.range_size, self.segment_offset)
25
27 return (self.locator == other.locator and
28 self.range_start == other.range_start and
29 self.range_size == other.range_size and
30 self.segment_offset == other.segment_offset)
31
33 block_start = 0
34
35
36
37
38 hi = len(data_locators)
39 lo = 0
40 i = (hi + lo) // 2
41 block_size = data_locators[i].range_size
42 block_start = data_locators[i].range_start
43 block_end = block_start + block_size
44
45
46
47
48 while not (range_start >= block_start and range_start < block_end):
49 if lo == i:
50
51 return None
52 if range_start > block_start:
53 lo = i
54 else:
55 hi = i
56 i = (hi + lo) // 2
57 block_size = data_locators[i].range_size
58 block_start = data_locators[i].range_start
59 block_end = block_start + block_size
60
61 return i
62
64 __slots__ = ("locator", "block_size", "segment_offset", "segment_size")
65
66 - def __init__(self, locator, block_size, segment_offset, segment_size):
67 self.locator = locator
68 self.block_size = block_size
69 self.segment_offset = segment_offset
70 self.segment_size = segment_size
71
73 return (self.locator == other.locator and
74 self.block_size == other.block_size and
75 self.segment_offset == other.segment_offset and
76 self.segment_size == other.segment_size)
77
79 return "LocatorAndRange(%r, %r, %r, %r)" % (self.locator, self.block_size, self.segment_offset, self.segment_size)
80
82 """Get blocks that are covered by a range.
83
84 Returns a list of LocatorAndRange objects.
85
86 :data_locators:
87 list of Range objects, assumes that blocks are in order and contiguous
88
89 :range_start:
90 start of range
91
92 :range_size:
93 size of range
94
95 :limit:
96 Maximum segments to return, default None (unlimited). Will truncate the
97 result if there are more segments needed to cover the range than the
98 limit.
99
100 """
101 if range_size == 0:
102 return []
103 resp = []
104 range_end = range_start + range_size
105
106 i = first_block(data_locators, range_start)
107 if i is None:
108 return []
109
110
111
112 while i < len(data_locators) and len(resp) != limit:
113 dl = data_locators[i]
114 block_start = dl.range_start
115 block_size = dl.range_size
116 block_end = block_start + block_size
117 _logger.log(RANGES_SPAM,
118 "L&R %s range_start %s block_start %s range_end %s block_end %s",
119 dl.locator, range_start, block_start, range_end, block_end)
120 if range_end <= block_start:
121
122 break
123
124 if range_start >= block_start and range_end <= block_end:
125
126 resp.append(LocatorAndRange(dl.locator, block_size, dl.segment_offset + (range_start - block_start), range_size))
127 elif range_start >= block_start and range_end > block_end:
128
129 resp.append(LocatorAndRange(dl.locator, block_size, dl.segment_offset + (range_start - block_start), block_end - range_start))
130 elif range_start < block_start and range_end > block_end:
131
132 resp.append(LocatorAndRange(dl.locator, block_size, dl.segment_offset, block_size))
133 elif range_start < block_start and range_end <= block_end:
134
135 resp.append(LocatorAndRange(dl.locator, block_size, dl.segment_offset, range_end - block_start))
136 block_start = block_end
137 i += 1
138 return resp
139
140 -def replace_range(data_locators, new_range_start, new_range_size, new_locator, new_segment_offset):
141 """
142 Replace a file segment range with a new segment.
143
144 NOTE::
145 data_locators will be updated in place
146
147 :data_locators:
148 list of Range objects, assumes that segments are in order and contiguous
149
150 :new_range_start:
151 start of range to replace in data_locators
152
153 :new_range_size:
154 size of range to replace in data_locators
155
156 :new_locator:
157 locator for new segment to be inserted
158
159 :new_segment_offset:
160 segment offset within the locator
161
162 """
163 if new_range_size == 0:
164 return
165
166 new_range_end = new_range_start + new_range_size
167
168 if len(data_locators) == 0:
169 data_locators.append(Range(new_locator, new_range_start, new_range_size, new_segment_offset))
170 return
171
172 last = data_locators[-1]
173 if (last.range_start+last.range_size) == new_range_start:
174 if last.locator == new_locator and (last.segment_offset+last.range_size) == new_segment_offset:
175
176 last.range_size += new_range_size
177 else:
178 data_locators.append(Range(new_locator, new_range_start, new_range_size, new_segment_offset))
179 return
180
181 i = first_block(data_locators, new_range_start)
182 if i is None:
183 return
184
185
186
187 while i < len(data_locators):
188 dl = data_locators[i]
189 old_segment_start = dl.range_start
190 old_segment_end = old_segment_start + dl.range_size
191 _logger.log(RANGES_SPAM,
192 "RR %s range_start %s segment_start %s range_end %s segment_end %s",
193 dl, new_range_start, old_segment_start, new_range_end,
194 old_segment_end)
195 if new_range_end <= old_segment_start:
196
197 break
198
199 if old_segment_start <= new_range_start and new_range_end <= old_segment_end:
200
201
202 if (new_range_start-old_segment_start) > 0:
203 data_locators[i] = Range(dl.locator, old_segment_start, (new_range_start-old_segment_start), dl.segment_offset)
204 data_locators.insert(i+1, Range(new_locator, new_range_start, new_range_size, new_segment_offset))
205 else:
206 data_locators[i] = Range(new_locator, new_range_start, new_range_size, new_segment_offset)
207 i -= 1
208 if (old_segment_end-new_range_end) > 0:
209 data_locators.insert(i+2, Range(dl.locator, new_range_end, (old_segment_end-new_range_end), dl.segment_offset + (new_range_start-old_segment_start) + new_range_size))
210 return
211 elif old_segment_start <= new_range_start and new_range_end > old_segment_end:
212
213
214 data_locators[i] = Range(dl.locator, old_segment_start, (new_range_start-old_segment_start), dl.segment_offset)
215 data_locators.insert(i+1, Range(new_locator, new_range_start, new_range_size, new_segment_offset))
216 i += 1
217 elif new_range_start < old_segment_start and new_range_end >= old_segment_end:
218
219
220 del data_locators[i]
221 i -= 1
222 elif new_range_start < old_segment_start and new_range_end < old_segment_end:
223
224
225 data_locators[i] = Range(dl.locator, new_range_end, (old_segment_end-new_range_end), dl.segment_offset + (new_range_end-old_segment_start))
226 return
227 i += 1
228