glean/rts/lookup.h (117 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include "glean/rts/fact.h" #include "glean/rts/id.h" #include "glean/rts/stats.h" #include <vector> namespace facebook { namespace glean { namespace rts { /** * An iterator for facts. * */ struct FactIterator { enum Demand { KeyOnly, KeyValue }; // Advance the iterator to the next fact. Calling this after get() returned // Fact::Ref::invalid() is not allowed. virtual void next() = 0; // Get the current fact. Demand says whether to include its value which might // be more expensive (rocksdb will do an additional lookup). virtual Fact::Ref get(Demand demand = KeyValue) = 0; virtual ~FactIterator() {} static std::unique_ptr<FactIterator> merge( std::unique_ptr<FactIterator> left, std::unique_ptr<FactIterator> right, size_t prefix_size ); static std::unique_ptr<FactIterator> append( std::unique_ptr<FactIterator> left, std::unique_ptr<FactIterator> right ); // Filter the facts of the underlying DB according to the provided // visibility function. It is the responsibility of the caller to // ensure that the resulting set of facts is valid (has no dangling // fact IDs). static std::unique_ptr<FactIterator> filter( std::unique_ptr<FactIterator> base, std::function<bool(Id id)> visible ); }; /** * An iterator which never returns any facts. * */ struct EmptyIterator final : FactIterator { void next() override {} Fact::Ref get(Demand) override { return Fact::Ref::invalid(); } }; /** * Interface for looking up fact definitions. * */ struct Lookup { virtual ~Lookup() {} // Lookup the Id of a fact by its type and key. Returns Id::INVALID if not // found. virtual Id idByKey(Pid type, folly::ByteRange key) = 0; // Lookup the type of a fact by its id. Returns Id::INVALID if not found. virtual Pid typeById(Id id) = 0; // Apply the function to the type, key and value of the fact with the given id // if it exists. Return value indicates whether the fact has been found. // If a type is supplied only facts with this type will be found. virtual bool factById( Id id, std::function<void(Pid, Fact::Clause)> f) = 0; /// Return a fact id such that no facts in the Enumerate have an id below it. /// There is no guarantee that a fact with this particular id exists but fact /// ids are supposed to be dense between startingId and firstFreeId. virtual Id startingId() const = 0; /// Return a fact id such that no facts in the Enumerate have an id equal to /// or greater than it. See comments on startingId. virtual Id firstFreeId() const = 0; /// Return bounds on how many facts for a particular predicate the Lookup has. virtual Interval count(Pid pid) const = 0; /// Return a FactIterator that enumerates all facts in increasing order of /// their ids, starting with 'from' and up to, but not including, 'upto'. /// Passing `Id::invalid` for either means starting with the first/finishing /// with the last fact. virtual std::unique_ptr<FactIterator> enumerate( Id from = Id::invalid(), Id upto = Id::invalid()) = 0; /// Return a FactIterator that enumerates all facts in descreasing order of /// their ids, starting from the first fact before 'from' and down to and /// including 'downto'. Passing `Id::invalid` for either means starting with /// the last/finishing with the first fact. /// /// Note that `from` is typically the fact id *one past* the first fact /// returned by the iterator and `downto` the fact id of the last fact /// returned by the iterator. This means that `enumerateBack(b,a)` produces /// exactly the same facts as `enumerate(a,b)`, just in reverse order. virtual std::unique_ptr<FactIterator> enumerateBack( Id from = Id::invalid(), Id downto = Id::invalid()) = 0; // Obtain a prefix iterator for the given predicate. The iterator covers keys // which begin with the first 'prefix_size' bytes of 'start', starting with // the first key not lexicographically less than 'start', and produces facts // in lexicographic order. In particular, setting 'prefix_size' to // 'start.size()' iterates over all keys with the prefix 'start'. virtual std::unique_ptr<FactIterator> seek( Pid type, folly::ByteRange start, size_t prefix_size ) = 0; }; /** * An implementation of Lookup which doesn't find any facts. * */ struct EmptyLookup final : Lookup { Id idByKey(Pid, folly::ByteRange) override { return Id::invalid(); } Pid typeById(Id) override { return Pid::invalid(); } bool factById(Id, std::function<void(Pid, Fact::Clause)>) override { return false; } Id startingId() const override { return Id::lowest(); } Id firstFreeId() const override { return Id::lowest(); } Interval count(Pid) const override { return 0; } std::unique_ptr<FactIterator> enumerate(Id, Id) override { return std::make_unique<EmptyIterator>(); } std::unique_ptr<FactIterator> enumerateBack(Id, Id) override { return std::make_unique<EmptyIterator>(); } std::unique_ptr<FactIterator> seek(Pid, folly::ByteRange, size_t) override { return std::make_unique<EmptyIterator>(); } static EmptyLookup& instance(); }; /** * A Lookup which ignores all facts with Ids from the given one up. Since we * assign Ids sequentially, this effectively implements a snapshot of the * database. * */ struct Snapshot : Lookup { Snapshot(Lookup *b, Id i) : base_(b), boundary_(i) {} Id idByKey(Pid type, folly::ByteRange key) override { auto id = base()->idByKey(type, key); return id < boundary() ? id : Id::invalid(); } Pid typeById(Id id) override { return id < boundary() ? base()->typeById(id) : Pid::invalid(); } bool factById(Id id, std::function<void(Pid, Fact::Clause)> f) override { return id < boundary() && base()->factById(id, std::move(f)); } Id startingId() const override { return std::min(base()->startingId(), boundary()); } Id firstFreeId() const override { return std::min(boundary(), base()->firstFreeId()); } Interval count(Pid pid) const override { return base_->count(pid).asHigh(); } std::unique_ptr<FactIterator> enumerate(Id from, Id upto) override; std::unique_ptr<FactIterator> enumerateBack(Id from, Id downto) override; std::unique_ptr<FactIterator> seek( Pid type, folly::ByteRange start, size_t prefix_size) override; Lookup *base() const { return base_; } Id boundary() const { return boundary_; } private: Lookup *base_; Id boundary_; }; } } }