Ticket #393: choose_segs3.py

File choose_segs3.py, 3.5 KB (added by zooko, at 2011-09-03T07:07:17Z)
Line 
1def 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 (first_segment_of_write == last_segment_of_current) and \
39            (offset == (first_segment_of_write * segsize)) and \
40            ((offset + length) >= filesize):
41        # If this segment is the last segment of the current file and we're
42        # overwriting all the bytes in this segment, then no need to fetch
43        # it.
44        fetch_first_segment = False
45    elif (offset == (first_segment_of_write * segsize)) and \
46            ((offset + length) >= ((first_segment_of_write+1) * segsize)):
47        # If we are overwriting the entire segment, then no need to fetch the
48        # current version.
49        fetch_first_segment = False
50
51    # If the last segment is also the first segment, then we're done.
52    if last_segment_of_write == first_segment_of_write:
53        return (first_segment, fetch_first_segment, first_segment, fetch_first_segment)
54
55    # Now let's figure out if we need to fetch the last segment.
56    fetch_last_segment = True
57
58    if last_segment_of_write > last_segment_of_current:
59        # If it is a segment that doesn't currently exist at all (it is past
60        # the end) then we don't need to fetch it.
61        fetch_last_segment = False
62    elif last_segment_of_write == last_segment_of_current:
63        # If this is the last segment of the current file and we are
64        # overwriting all of the bytes in this segment, then we don't need to fetch it.
65        if offset + length >= filesize:
66            fetch_last_segment = False
67    else:
68        # If we are overwriting the entire segment, then no need to fetch the
69        # current version.
70        if (offset + length) % segsize == 0:
71            fetch_last_segment = False
72       
73    return (first_segment, fetch_first_segment, last_segment, fetch_last_segment)