From 9b44f6e5ed0a8f165468d4b6b6a21944c9d986f1 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Mon, 13 Apr 2026 20:53:02 -0400 Subject: [PATCH] (#93) Index mapper will now only extract Key tuple items --- CHANGELOG.md | 8 ++++++++ lib/ecto_foundationdb/indexer/default.ex | 17 ++++++++++++----- mix.exs | 2 +- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8eb4d7b..36d53eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v0.7.4 (2026-04-13) + +### Bug fixes + +* (#93) Fixed the Mapper used by GetMappedRange, critical for rare cases when the server attempts to fully tuple-decode + an Incomplete Versionstamp in the value portion of the Index Entry instead of lazy evaluation. We believe this could + cause Error 2042: "The value cannot be parsed as a tuple" in rare cases. + ## v0.7.3 (2026-04-06) ### Bug fixes diff --git a/lib/ecto_foundationdb/indexer/default.ex b/lib/ecto_foundationdb/indexer/default.ex index 46ec712..8273590 100644 --- a/lib/ecto_foundationdb/indexer/default.ex +++ b/lib/ecto_foundationdb/indexer/default.ex @@ -186,7 +186,7 @@ defmodule EctoFoundationDB.Indexer.Default do # same transaction. So, we must choose either the key or the value of the index entry. # A natural choice is to use the value to have the versionstamp so that # get_mapped_range works correctly. However, then we lose the ability to manage the index - # on updates and clears. Therefore, we must put the versionstamp in the index_key and + # on updates and clears. Therefore, we must put the versionstamp in the index_key, # which forces our mapper to inspect both the key and value to extract the pk. # # This means that the value portion of the index kv will always be written with an @@ -393,18 +393,25 @@ defmodule EctoFoundationDB.Indexer.Default do """ end - # See key-value design in get_index_entry defp mapper(tenant, idx_len) do + # (#93) We choose to extract all items from the Key, because when Versionstamps are in play, + # the Value is not actually a valid tuple. It contains the incomplete versionstamp, which + # which has a short trailing portion. If FDB allowed us to set_versionstamp_key_and_value + # then we'd be free to define the mapper on either the key or the value. But since we are + # forced to pick set_versionstamped_key, which must also extract the tuple items from the + # Key. + # + # Also see key-value design in get_index_entry and set_index_entry for more details. offset_fun = fn offset -> [ # prefix - "{V[#{offset}]}", + "{K[#{offset}]}", # source - "{V[#{offset + 1}]}", + "{K[#{offset + 1}]}", # namespace - "{V[#{offset + 2}]}", + "d", # pk: get it from the index_key because the versionstamp lives there, not in the value "{K[#{offset + 5 + idx_len}]}", diff --git a/mix.exs b/mix.exs index 22c2ac9..6bb3e0d 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule EctoFoundationdb.MixProject do def project do [ app: :ecto_foundationdb, - version: "0.7.3", + version: "0.7.4", description: "FoundationDB adapter for Ecto", elixir: "~> 1.15", start_permanent: Mix.env() == :prod,