fetch

    /// Execute the query, returning the result (often, the result
    /// will be memoized).  This is the "main method" for
    /// queries.
    ///
    /// Returns `Err` in the event of a cycle, meaning that computing
    /// the value for this `key` is recursively attempting to fetch
    /// itself.
    fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value;

fetch 方法计算查询的值。最好在可能的情况下重复使用已记忆的值。

输入查询

输入查询只是从表中加载结果。

Interned 查询

Interned 查询将输入映射到 hashmap 中以查找现有的整数。如果不存在,则会创建一个新值。

Derived queries

派生查询

派生查询的逻辑更为复杂。这里总结一下高级别的想法,但你可能会发现流程图有助于深入挖掘。

术语一章也可能很有用;在某些情况下,我们会链接到有关单词首次用法的部分。

  • 如果 memo 已存在,则检查该备忘录是否在当前修订版本 (revision) 中进行了验证 (verified)。
    • 如果是,则比较它更改所在 (changed at) 修订,并适当地返回 true 或 false。
  • 如果 memo 不存在,则必须检查依赖项 (dependencies) 是否已被修改:
    • 设 R 是上次验证 memo 的修订版本;我们希望知道自修订 R 以来,是否有任何依赖项被更改。
    • 首先,检查持久性 (durability)。对于每个 memo,跟踪 memo 依赖项的最小持久性。如果 memo 具有持久性 D,并且自上次验证以来,持久性为 D 的输入没有任何更改,则可以认为 memo 已验证,从而无需任何进一步工作。
    • 如果持久性检查不够充分,则必须逐个检查依赖项。为此,需迭代每个依赖项 D,并调用 maybe_changed_after 操作以检查自修订版本 R 以来 D 是否已更改。
    • 如果未修改依赖项:将 memo 标记为已验证,并使用其在更改所在的修订以返回 true 或 false。
    • 如果依赖项已修改:
      • 执行使用者的查询函数(与 fetch 相同),这可能会回溯 (backdate) 结果值。
  • 假设依赖项已经被修改或者 memo 不包含被记忆的值:
    • 则执行使用者的查询功能
    • 然后,计算被记忆的值最后被更改的修订版本:
      • 回溯:如果此前被记忆的值存在,并且新值等于该旧值,则回溯 memo,这意味着使用以前的 changed_at 修订
        • 由于回溯,查询的依赖可能在某个修订 R1 中改变,但是查询的结果在 R2 先于 R1 的某个修订中改变
      • 否则,使用当前版本
    • 为新值构造一个 memo 并返回它