1 | def choose_segs(filesize, segsize, offset, length): |
---|
2 | """ |
---|
3 | What segments do you need to write to, and to read from, given an |
---|
4 | filesize-byte file, split into segsize-byte segments, the last one of |
---|
5 | which could be fewer than segsize bytes, and an offset and non-zero |
---|
6 | length that needs to be written? Those are the inputs to the |
---|
7 | algorithm. The output is: first_segment (int), fetch_first_segment |
---|
8 | (boolean), last_segment (int), fetch_last_segment (boolean). The meaning |
---|
9 | of "fetch" is: "We have to fetch the current value of this segment in |
---|
10 | order to compute what the new value of the segment should be.". That is |
---|
11 | true whenever the write is writing part of the segment and leaving other |
---|
12 | bytes within the segment with their current value. |
---|
13 | |
---|
14 | The only constraints on the output are that last_segment >= |
---|
15 | first_segment, and that if last_segment == first_segment then |
---|
16 | fetch_last_segment == first_first_segment. |
---|
17 | """ |
---|
18 | precondition(filesize >= 0, filesize) |
---|
19 | precondition(segsize >= 1, segsize) |
---|
20 | precondition(offset >= 0, offset) |
---|
21 | precondition(length >= 1, length) |
---|
22 | |
---|
23 | first_segment_of_write = offset // segsize |
---|
24 | last_byte_of_write = offset + length - 1 |
---|
25 | last_segment_of_write = last_byte_of_write // segsize |
---|
26 | |
---|
27 | num_segs_in_current = div_ceil(filesize, segsize) |
---|
28 | last_segment_of_current = num_segs_in_current - 1 |
---|
29 | |
---|
30 | # Now let's figure out if we need to fetch the first segment. Initialize |
---|
31 | # fetch_last_segment to True and then check whether we don't actually |
---|
32 | # need to fetch it. |
---|
33 | fetch_first_segment = True |
---|
34 | if first_segment_of_write > last_segment_of_current: |
---|
35 | # If it is a segment that doesn't currently exist at all (it is past |
---|
36 | # the end) then we don't need to fetch it. |
---|
37 | fetch_first_segment = False |
---|
38 | elif (offset == (first_segment_of_write * segsize)) and \ |
---|
39 | ((offset + length) >= ((first_segment_of_write+1) * segsize)): |
---|
40 | # If we are overwriting the entire segment, then no need to fetch the |
---|
41 | # current version. |
---|
42 | fetch_first_segment = False |
---|
43 | |
---|
44 | # If the last segment is also the first segment, then we're done. |
---|
45 | if last_segment_of_write == first_segment_of_write: |
---|
46 | return (first_segment, fetch_first_segment, first_segment, fetch_first_segment) |
---|
47 | |
---|
48 | # Now let's figure out if we need to fetch the last segment. |
---|
49 | fetch_last_segment = True |
---|
50 | |
---|
51 | if last_segment_of_write > last_segment_of_current: |
---|
52 | # If it is a segment that doesn't currently exist at all (it is past |
---|
53 | # the end) then we don't need to fetch it. |
---|
54 | fetch_last_segment = False |
---|
55 | elif last_segment_of_write == last_segment_of_current: |
---|
56 | # If this is the last segment of the current file and we are |
---|
57 | # overwriting all of the bytes in this segment, then we don't need to fetch it. |
---|
58 | if offset + length >= filesize: |
---|
59 | fetch_last_segment = False |
---|
60 | else: |
---|
61 | # If we are overwriting the entire segment, then no need to fetch the |
---|
62 | # current version. |
---|
63 | if (offset + length) % segsize == 0: |
---|
64 | fetch_last_segment = False |
---|
65 | |
---|
66 | return (first_segment, fetch_first_segment, last_segment, fetch_last_segment) |
---|