aboutsummaryrefslogtreecommitdiffstats
path: root/document/src/vespa/document/select/gid_filter.h
blob: 7e7816f4c65af6c61d73adc53d7f6daa7772ae4e (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include <vespa/document/base/globalid.h>

namespace document::select {

class Node;

/**
 * This class allows for very quickly and cheaply filtering away metadata
 * entries that may not possibly match a document selection with a location
 * predicate, based on nothing but the GIDs in the metadata. This avoids
 * having to fetch the document IDs or whole documents themselves from
 * potentially slow storage in order to evaluate the selection in full.
 */
class GidFilter {
public:
    // GCC <= 5.3 has a bug where copying a boost::optional at certain -O
    // levels causes a erroneous compiler warning.
    // Using our own poor-man's optional for now.
    // TODO: replace with std::otional once on a C++17 stdlib.
    struct OptionalLocation {
        uint32_t _location;
        bool _valid;

        OptionalLocation() : _location(0), _valid(false) {}

        explicit OptionalLocation(uint32_t location)
            : _location(location),
              _valid(true)
        {
        }
    };
private:
    OptionalLocation _required_gid_location;

    /**
     * Lifetime of AST Node pointed to does not have to extend beyond the call
     * to this constructor.
     */
    explicit GidFilter(const Node& ast_root);
public:
    /**
     * No-op filter; everything matches always.
     */
    GidFilter()
        : _required_gid_location()
    {
    }

    /**
     * A GidFilter instance may be safely and cheaply copied. No dependencies
     * exist on the life time of the AST from which it was created.
     */
    GidFilter(const GidFilter&) = default;
    GidFilter& operator=(const GidFilter&) = default;

    /**
     * Create a filter with a location inferred from the provided selection.
     * If the selection does not contain a location predicate, the GidFilter
     * will effectively act as a no-op which assumes every document may match.
     *
     * It is safe to use the resulting GidFilter even if the lifetime of the
     * Node pointed to by ast_root does not extend beyond this call; the
     * GidFilter does not store any implicit or explicit references to it.
     */
    static GidFilter for_selection_root_node(const Node& ast_root) {
        return GidFilter(ast_root);
    }

    /**
     * Returns false iff there exists no way that a document whose ID has the
     * given GID can possibly match the selection. This currently only applies
     * if the document selection contains a location-based predicate (i.e.
     * id.user or id.group).
     *
     * As the name implies this is a probabilistic match; it's possible for
     * this function to return true even if the document selection matched
     * against the full document/documentid would return false.
     */
    bool gid_might_match_selection(const GlobalId& gid) const {
        const uint32_t gid_location = gid.getLocationSpecificBits();
        return (!_required_gid_location._valid
                || (gid_location == _required_gid_location._location));
    }
};

}