summaryrefslogtreecommitdiffstats
path: root/memfilepersistence/src/vespa/memfilepersistence/mapper/locationreadplanner.cpp
blob: 3dadceb1e2ef13b589cc1540d0940280e012f240 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "locationreadplanner.h"
#include <vespa/memfilepersistence/memfile/memfileiointerface.h>

namespace storage {
namespace memfile {

LocationDiskIoPlanner::LocationDiskIoPlanner(
        const MemFileIOInterface& io,
        DocumentPart part,
        const std::vector<DataLocation>& desiredLocations,
        uint32_t maxGap,
        uint32_t blockStartIndex)
    : _io(io),
      _operations(),
      _part(part),
      _blockStartIndex(blockStartIndex)
{
    processLocations(desiredLocations, maxGap);
}

namespace {
    uint32_t alignDown(uint32_t value) {
        uint32_t blocks = value / 512;
        return blocks * 512;
    };

    uint32_t alignUp(uint32_t value) {
        uint32_t blocks = (value + 512 - 1) / 512;
        return blocks * 512;
    };
}

void
LocationDiskIoPlanner::scheduleLocation(DataLocation loc,
                                        std::vector<DataLocation>& ops)
{
    if (!_io.isCached(loc, _part) && loc._size) {
        // Convert the relative location from the buffer to an
        // absolute location.
        ops.push_back(DataLocation(loc._pos + _blockStartIndex,
                                   loc._size));
    }
}

void
LocationDiskIoPlanner::processLocations(
        const std::vector<DataLocation>& desiredLocations,
        uint32_t maxGap)
{
    // Build list of disk read operations to do
    std::vector<DataLocation> allOps;

    // Create list of all locations we need to read
    for (std::size_t i = 0; i < desiredLocations.size(); ++i) {
        scheduleLocation(desiredLocations[i], allOps);
    }

    // Sort list, and join elements close together into single IO ops
    std::sort(allOps.begin(), allOps.end());
    for (size_t i = 0; i < allOps.size(); ++i) {
        uint32_t start = alignDown(allOps[i]._pos);
        uint32_t stop = alignUp(allOps[i]._pos + allOps[i]._size);
        if (i != 0) {
            uint32_t lastStop = _operations.back()._pos
                              + _operations.back()._size;
            if (lastStop >= start || start - lastStop < maxGap) {
                _operations.back()._size += (stop - lastStop);
                continue;
            }
        }

        _operations.push_back(DataLocation(start, stop - start));
    }
}

uint32_t
LocationDiskIoPlanner::getTotalBufferSize() const
{
    uint32_t totalSize = 0;
    for (size_t i = 0; i < _operations.size(); ++i) {
        totalSize += _operations[i]._size;
    }
    return totalSize;
}

void
LocationDiskIoPlanner::print(std::ostream& out, bool verbose,
                             const std::string& indent) const
{
    (void) verbose; (void) indent;
    for (std::size_t i = 0; i < _operations.size(); ++i) {
        if (i > 0) out << ",";
        out << "[" << _operations[i]._pos << ","
            << (_operations[i]._size + _operations[i]._pos) << "]";
    }
}

} // memfile
} // storage