Skip to content

BE-2: Use the Postgres clock for writing timestamps and resolving temporal axes - #9111

Draft
claude[bot] wants to merge 5 commits into
mainfrom
c/be-2-use-postgres-clock-for-timestamps
Draft

BE-2: Use the Postgres clock for writing timestamps and resolving temporal axes#9111
claude[bot] wants to merge 5 commits into
mainfrom
c/be-2-use-postgres-clock-for-timestamps

Conversation

@claude

@claude claude Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Requested by Tim Diekmann · Slack thread

🌟 What is the purpose of this PR?

Before: the Graph resolved temporal axes (the "now" a query runs against) with the host's clock, while ontology writes stamp rows with the Postgres clock. With any drift between the two (~50 ms is enough), a client could archive an entity type and still get it back from the next read, or unarchive it and have it stay invisible — the read's "now" lands on the wrong side of the interval bound the write just recorded. Entity writes were host-clock-stamped too, so DB-now()-based lookups (e.g. user-by-email) had the mirror-image race.

After: the Postgres clock is the only clock for query-relevant timestamps. Reads resolve their temporal axes with a timestamp read from the database, and all writes — entity and ontology alike — take their transaction time from a database clock reading fetched once per operation and passed to every statement as a parameter. Archive-then-read and unarchive-then-read are consistent regardless of host clock drift, and all timestamps within one operation share a single value.

How (zero extra round trips on the hot paths): every operation already starts by building PolicyComponents, whose first statement is the determine_actor actor lookup. That statement now additionally returns statement_timestamp(), and PolicyComponents carries the reading so all resolve_with(...) calls and write stamps of the operation reuse it. statement_timestamp() (rather than now()) is used for all database clock reads: it aligns with the REPEATABLE READ snapshot (taken at the transaction's first statement, not at BEGIN) and it still advances per statement inside a shared transaction — the integration-test harness runs each test in one rollback transaction, where a frozen now() gives distinct operations identical timestamps (and empty, undecodable intervals for archive-after-create).

🔗 Related links

🔍 What does this change?

  • hash-graph-authorization:
    • PrincipalStore gains determine_actor_with_timestamp (actor lookup + statement_timestamp() in one statement; for the public actor only the clock is read) and current_timestamp (standalone clock read, used as a fallback).
    • PolicyComponents carries the database clock reading, exposed via PolicyComponents::timestamp(); the builder accepts with_timestamp(...) for callers that already captured the operation's reading.
  • hash-graph-store: the parameterless QueryTemporalAxesUnresolved::resolve() is removed — callers must supply a timestamp via resolve_with(...), so the host clock can no longer leak into query resolution.
  • hash-graph-postgres-store, read paths:
    • All 21 production resolution call sites now use resolve_with(...) with the operation's database timestamp: entity reads (query_entities, query_entity_subgraph, summarize_entities, get_entity_by_id), ontology reads (query/count/subgraph for data/property/entity types), has_permission_for_*, and the StoreProvider validation lookups (which now carry the surrounding operation's timestamp).
    • query_entities/query_entity_subgraph previously resolved twice per request (query pass and permission pass) with two different host-clock values; both passes now share the one database reading.
  • hash-graph-postgres-store, write paths:
    • create_entities takes its transaction time from its first in-transaction statement (the actor lookup) instead of the host clock before the transaction; remove_nanosecond() is dropped there since Postgres timestamps are µs-precision by construction.
    • patch_entity takes its transaction time from lock_entity_edition, whose SQL now filters on COALESCE($n, statement_timestamp()) and returns the reading (LockedEntityEdition::locked_at); a client-supplied decision time is still honoured in the lock's WHERE.
    • Entity deletion reads the clock from the write transaction instead of Timestamp::now().
    • Ontology writes (create_ontology_temporal_metadata, archive_ontology_type, unarchive_ontology_type, and their create_ontology_metadata / update_owned_ontology_id wrappers) no longer stamp with inline SQL now(): they take the operation's database clock reading as a parameter — archive/unarchive reuse the PolicyComponents reading, create/update fetch one at the start of their transaction. This gives distinct per-operation stamps even when operations share a transaction, while all statements of one operation still share a single value.
    • Snapshot-restore validation reads the clock once for its provider.
  • Integration tests: an archive → assert-gone → unarchive → assert-back round-trip test for ontology types (none existed), and a test asserting the resolved pinned timestamp of a subgraph response is bracketed by two database clock readings.

Round-trip accounting: authenticated reads and entity writes get the timestamp for free from the existing actor-lookup statement. A standalone SELECT statement_timestamp() only happens on paths that never ran the lookup first: ontology create/update transactions, public-actor requests, PolicyComponents built from an already-resolved ActorId without a supplied timestamp (create_web, policy CRUD internals), entity deletion, snapshot restore, and the get_closed_multi_entity_types REST endpoint. No hot read path pays an extra round trip.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Policy tables (policy_edition etc.) still stamp with inline SQL now(). They are not resolved through QueryTemporalAxes and are read with SQL-side now() comparisons on the same database clock, so they are unaffected by the drift this PR fixes; moving them onto the parameterized mechanism would be a mechanical follow-up.
  • The [patch.crates-io] git pins (libp2p et al.) are unreachable from the sandbox this was authored in, so local cargo check/clippy/nextest could not run at all — rustfmt passes and the diff was reviewed carefully, but compile and test verification is deferred to CI. The Cargo.lock change is the single hand-added dependency edge for hash-graph-authorizationhash-graph-temporal-versioning (workspace members carry no checksums); mise was likewise unavailable, so the generated package.json wiring was mirrored by hand exactly like sibling crates.

🐾 Next steps

  • A clippy disallowed-methods guardrail for Timestamp::now()/OffsetDateTime::now_utc() in the store crates could enforce this statically; left out to avoid noise from the legitimate test-only uses.
  • When BE-332 moves authentication into the Graph, its auth statement becomes the natural first statement of PolicyComponents building and should keep returning the clock reading.
  • Interval::from_sql still panics (unimplemented!) on empty ranges. No write path can produce one anymore (per-operation stamps are strictly increasing within a transaction), but decoding one defensively as an error would be safer.

🛡 What tests cover this?

  • New: archive_unarchive_round_trip and resolved_temporal_axes_use_database_clock in tests/graph/integration/postgres/data_type.rs. The round-trip test also guards the ontology write stamps: with transaction-frozen now() stamps it fails inside the rollback-transaction harness (archive of a type created in the same test produced an empty, undecodable interval).
  • Existing: the full graph integration suite exercises every rewired read/write path; query/compile/tests.rs covers the compiler against explicitly resolved axes.

❓ How to test this?

  1. Run the graph integration tests (cargo nextest run --package hash-graph-integration) against a local Postgres.
  2. For the original repro: run Postgres with a clock offset from the host (e.g. under a VM whose clock drifts ahead), then create → archive → query and unarchive → query an entity type via the REST API; the query results now flip immediately with the write.

…poral axes

Temporal axes were resolved with the graph host's clock while ontology
writes stamp rows with the Postgres clock, so any drift between the two
made archive/unarchive-then-read return stale results. The database
clock is now the single time authority:

- `determine_actor` gains a sibling `determine_actor_with_timestamp`
  which returns `statement_timestamp()` from the same statement, and
  `PolicyComponents` carries that reading so every operation gets a
  database clock value without an extra round trip.
- All production `QueryTemporalAxesUnresolved::resolve()` call sites now
  use `resolve_with` with the operation's database timestamp; the
  parameterless `resolve()` is removed so the host clock can no longer
  leak into query resolution.
- Entity writes source their transaction time from the database:
  `create_entities` from its first in-transaction statement,
  `patch_entity` from the locking statement (which now filters on and
  returns `statement_timestamp()`), and entity deletion from a
  `current_timestamp` read on the write transaction.
- Adds an archive/unarchive round-trip integration test and a test
  asserting resolved axes come from the database clock.
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Jul 27, 2026 4:01pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jul 27, 2026 4:01pm
petrinaut Skipped Skipped Comment Jul 27, 2026 4:01pm

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team area/tests New or updated tests labels Jul 27, 2026
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 2.19780% with 178 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.26%. Comparing base (0f28b50) to head (3d66419).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...s-store/src/store/postgres/ontology/entity_type.rs 0.00% 62 Missing ⚠️
...cal/graph/postgres-store/src/store/postgres/mod.rs 0.00% 39 Missing ⚠️
...cal/graph/authorization/src/policies/components.rs 10.00% 36 Missing ⚠️
...s-store/src/store/postgres/knowledge/entity/mod.rs 0.00% 12 Missing ⚠️
...res-store/src/store/postgres/ontology/data_type.rs 0.00% 8 Missing ⚠️
...store/src/store/postgres/ontology/property_type.rs 0.00% 6 Missing ⚠️
...local/graph/postgres-store/src/store/validation.rs 0.00% 6 Missing ⚠️
.../graph/postgres-store/src/snapshot/entity/batch.rs 0.00% 5 Missing ⚠️
...tore/src/store/postgres/knowledge/entity/delete.rs 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9111      +/-   ##
==========================================
- Coverage   59.31%   59.26%   -0.05%     
==========================================
  Files        1406     1406              
  Lines      135972   136087     +115     
  Branches     6376     6380       +4     
==========================================
+ Hits        80650    80655       +5     
- Misses      54338    54448     +110     
  Partials      984      984              
Flag Coverage Δ
apps.hash-ai-worker-ts 1.99% <ø> (ø)
apps.hash-api 12.08% <ø> (ø)
local.hash-backend-utils 2.55% <ø> (ø)
local.hash-graph-sdk 10.02% <ø> (ø)
local.hash-isomorphic-utils 5.76% <ø> (-0.05%) ⬇️
rust.hash-graph-api 7.41% <ø> (ø)
rust.hash-graph-postgres-store 25.94% <0.00%> (-0.11%) ⬇️
rust.hashql-compiletest 28.39% <ø> (ø)
rust.hashql-eval 79.82% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread tests/graph/integration/postgres/data_type.rs Fixed
@codspeed-hq

codspeed-hq Bot commented Jul 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 98 untouched benchmarks


Comparing c/be-2-use-postgres-clock-for-timestamps (3d66419) with main (2b7e81d)

Open in CodSpeed

`yarn install --immutable` rejects the install when a package.json
declares a dependency the lockfile does not record. Also import `Cow`
from `alloc` to match the integration-test crate's convention.
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 27, 2026 14:40 Inactive
Comment thread libs/@local/graph/authorization/src/policies/components.rs Fixed
- add the `timestamp` field to the remaining `PolicyComponents` test
  initializer
- drop the `EntityTypeStore` trait import which is no longer used now
  that the entity read paths call the inherent
  `get_closed_multi_entity_types_impl`
- expect `clippy::too_many_lines` on `execute_entity_deletion`
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 27, 2026 14:50 Inactive
Clippy's `missing_const_for_fn` flags `set_timestamp`, and making it
const makes `with_timestamp` const-eligible as well.
Ontology create/archive/unarchive statements stamped rows with inline
SQL `now()`, which is frozen for the lifetime of a transaction. Inside
a shared transaction — such as the integration-test harness's rollback
transaction — archiving a type created earlier in the same transaction
therefore produced an empty interval, which cannot be decoded when the
statement returns it.

The statements now take the operation's database clock reading as a
parameter, like the entity write paths: archive/unarchive reuse the
reading carried by their `PolicyComponents`, while create/update fetch
one at the start of their transaction. All statements of one operation
keep sharing a single value, and separate operations get distinct
stamps even within one transaction.
@github-actions

Copy link
Copy Markdown
Contributor

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$27.6 \mathrm{ms} \pm 178 \mathrm{μs}\left({\color{gray}-2.642 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.49 \mathrm{ms} \pm 24.8 \mathrm{μs}\left({\color{gray}-3.618 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$13.5 \mathrm{ms} \pm 110 \mathrm{μs}\left({\color{gray}-1.475 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$44.8 \mathrm{ms} \pm 522 \mathrm{μs}\left({\color{gray}0.167 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$15.1 \mathrm{ms} \pm 146 \mathrm{μs}\left({\color{lightgreen}-6.933 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$25.4 \mathrm{ms} \pm 209 \mathrm{μs}\left({\color{gray}-0.238 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$29.3 \mathrm{ms} \pm 285 \mathrm{μs}\left({\color{gray}-0.367 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.80 \mathrm{ms} \pm 23.7 \mathrm{μs}\left({\color{gray}-3.857 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$14.8 \mathrm{ms} \pm 154 \mathrm{μs}\left({\color{gray}-0.356 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.93 \mathrm{ms} \pm 26.5 \mathrm{μs}\left({\color{gray}0.445 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.08 \mathrm{ms} \pm 18.2 \mathrm{μs}\left({\color{gray}-0.122 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$3.46 \mathrm{ms} \pm 22.0 \mathrm{μs}\left({\color{gray}0.160 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.39 \mathrm{ms} \pm 46.1 \mathrm{μs}\left({\color{gray}0.539 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.64 \mathrm{ms} \pm 26.0 \mathrm{μs}\left({\color{gray}0.619 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$4.26 \mathrm{ms} \pm 26.7 \mathrm{μs}\left({\color{gray}0.859 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.57 \mathrm{ms} \pm 28.7 \mathrm{μs}\left({\color{gray}-0.351 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.56 \mathrm{ms} \pm 19.9 \mathrm{μs}\left({\color{gray}0.045 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.21 \mathrm{ms} \pm 29.0 \mathrm{μs}\left({\color{gray}-0.105 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.74 \mathrm{ms} \pm 19.4 \mathrm{μs}\left({\color{gray}-0.576 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.57 \mathrm{ms} \pm 15.8 \mathrm{μs}\left({\color{gray}-1.010 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$2.73 \mathrm{ms} \pm 17.6 \mathrm{μs}\left({\color{gray}0.411 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$3.02 \mathrm{ms} \pm 21.0 \mathrm{μs}\left({\color{gray}-0.553 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.80 \mathrm{ms} \pm 21.5 \mathrm{μs}\left({\color{gray}-0.627 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$3.02 \mathrm{ms} \pm 23.3 \mathrm{μs}\left({\color{gray}0.585 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.09 \mathrm{ms} \pm 16.5 \mathrm{μs}\left({\color{gray}-0.324 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.81 \mathrm{ms} \pm 15.9 \mathrm{μs}\left({\color{gray}0.153 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$3.06 \mathrm{ms} \pm 26.9 \mathrm{μs}\left({\color{gray}-0.504 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.52 \mathrm{ms} \pm 20.5 \mathrm{μs}\left({\color{gray}-0.148 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.05 \mathrm{ms} \pm 18.3 \mathrm{μs}\left({\color{gray}0.309 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$3.37 \mathrm{ms} \pm 21.9 \mathrm{μs}\left({\color{gray}0.257 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.45 \mathrm{ms} \pm 21.8 \mathrm{μs}\left({\color{gray}-1.225 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.03 \mathrm{ms} \pm 21.5 \mathrm{μs}\left({\color{gray}0.669 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.45 \mathrm{ms} \pm 32.1 \mathrm{μs}\left({\color{gray}0.566 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$44.0 \mathrm{ms} \pm 272 \mathrm{μs}\left({\color{gray}-1.061 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$34.7 \mathrm{ms} \pm 211 \mathrm{μs}\left({\color{gray}-0.287 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$37.5 \mathrm{ms} \pm 258 \mathrm{μs}\left({\color{gray}-0.965 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$33.3 \mathrm{ms} \pm 224 \mathrm{μs}\left({\color{gray}-0.324 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$44.9 \mathrm{ms} \pm 239 \mathrm{μs}\left({\color{gray}1.86 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$51.5 \mathrm{ms} \pm 460 \mathrm{μs}\left({\color{gray}-0.850 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$42.3 \mathrm{ms} \pm 209 \mathrm{μs}\left({\color{gray}0.733 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$95.7 \mathrm{ms} \pm 589 \mathrm{μs}\left({\color{gray}1.38 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$46.5 \mathrm{ms} \pm 3.64 \mathrm{ms}\left({\color{red}31.7 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$316 \mathrm{ms} \pm 1.18 \mathrm{ms}\left({\color{gray}1.39 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$11.5 \mathrm{ms} \pm 70.6 \mathrm{μs}\left({\color{gray}-0.500 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$11.8 \mathrm{ms} \pm 68.3 \mathrm{μs}\left({\color{gray}0.013 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$11.8 \mathrm{ms} \pm 71.3 \mathrm{μs}\left({\color{gray}0.163 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$11.7 \mathrm{ms} \pm 81.1 \mathrm{μs}\left({\color{gray}0.841 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$11.7 \mathrm{ms} \pm 94.0 \mathrm{μs}\left({\color{gray}0.305 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$11.6 \mathrm{ms} \pm 91.0 \mathrm{μs}\left({\color{gray}1.37 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$11.8 \mathrm{ms} \pm 91.1 \mathrm{μs}\left({\color{gray}0.428 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$11.7 \mathrm{ms} \pm 68.4 \mathrm{μs}\left({\color{gray}0.505 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$11.9 \mathrm{ms} \pm 78.2 \mathrm{μs}\left({\color{gray}1.19 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$12.2 \mathrm{ms} \pm 84.4 \mathrm{μs}\left({\color{gray}1.45 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$12.0 \mathrm{ms} \pm 84.0 \mathrm{μs}\left({\color{gray}0.221 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$12.1 \mathrm{ms} \pm 143 \mathrm{μs}\left({\color{gray}-0.474 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$11.9 \mathrm{ms} \pm 66.4 \mathrm{μs}\left({\color{gray}-0.901 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$12.0 \mathrm{ms} \pm 68.4 \mathrm{μs}\left({\color{gray}-0.278 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$12.1 \mathrm{ms} \pm 80.7 \mathrm{μs}\left({\color{gray}-0.487 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$12.0 \mathrm{ms} \pm 83.8 \mathrm{μs}\left({\color{gray}-0.380 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$12.1 \mathrm{ms} \pm 79.6 \mathrm{μs}\left({\color{gray}-1.058 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$12.1 \mathrm{ms} \pm 72.1 \mathrm{μs}\left({\color{gray}-2.167 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$12.0 \mathrm{ms} \pm 69.1 \mathrm{μs}\left({\color{gray}-0.274 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$8.94 \mathrm{ms} \pm 52.3 \mathrm{μs}\left({\color{gray}-0.308 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$61.6 \mathrm{ms} \pm 551 \mathrm{μs}\left({\color{gray}-0.447 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$118 \mathrm{ms} \pm 521 \mathrm{μs}\left({\color{gray}0.181 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$70.0 \mathrm{ms} \pm 562 \mathrm{μs}\left({\color{gray}1.57 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$81.0 \mathrm{ms} \pm 654 \mathrm{μs}\left({\color{gray}1.03 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$90.6 \mathrm{ms} \pm 479 \mathrm{μs}\left({\color{gray}2.04 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$96.7 \mathrm{ms} \pm 587 \mathrm{μs}\left({\color{gray}2.06 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$46.7 \mathrm{ms} \pm 276 \mathrm{μs}\left({\color{gray}1.72 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$78.0 \mathrm{ms} \pm 395 \mathrm{μs}\left({\color{gray}3.94 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$53.1 \mathrm{ms} \pm 341 \mathrm{μs}\left({\color{gray}1.65 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$64.6 \mathrm{ms} \pm 389 \mathrm{μs}\left({\color{gray}4.47 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$67.1 \mathrm{ms} \pm 398 \mathrm{μs}\left({\color{gray}3.19 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$66.3 \mathrm{ms} \pm 293 \mathrm{μs}\left({\color{gray}3.79 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$114 \mathrm{ms} \pm 780 \mathrm{μs}\left({\color{lightgreen}-11.840 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$127 \mathrm{ms} \pm 681 \mathrm{μs}\left({\color{lightgreen}-9.900 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$20.3 \mathrm{ms} \pm 131 \mathrm{μs}\left({\color{gray}0.011 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$541 \mathrm{ms} \pm 1.30 \mathrm{ms}\left({\color{gray}-3.676 \mathrm{\%}}\right) $$ Flame Graph

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/deps Relates to third-party dependencies (area) area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team

Development

Successfully merging this pull request may close these issues.

3 participants