Implement String interning store - #7111
Conversation
3e5493a to
8e3a621
Compare
| ) extends InternedStringStore | ||
| with NamedLogging { | ||
|
|
||
| override def getOrIntern(value: String)(implicit tc: TraceContext): Future[InternedId] = { |
There was a problem hiding this comment.
the query proposed in the design was:
with new_row as (
insert into interned_strings (value) values ($v)
on conflict (value) do nothing returning id
)
select id from new_row union all select id from interned_strings where value = $v limit 1;
this does not work with contention:
[info] - handle concurrent interning of the same value without cache *** FAILED ***
[info] java.util.NoSuchElementException: empty result setSome( when invoking statement
[info] with new_row as (
[info] insert into interned_strings (value) values (?)
[info] on conflict (value) do nothing returning id
[info] )
[info] select id from new_row union all select id from interned_strings where value = ? limit 1;
[info] )
the reason for that is that if there's two queries, you can end up in this situation (as far as I understand):
- q1 runs the insert successfully
- q2 runs the insert which conflicts and returns nothing
- q2 runs the select which returns nothing
- q2 returns nothing
- q1 commits
There was a problem hiding this comment.
And q1 returns the right set?
There was a problem hiding this comment.
yeah but q2 returns nothing
There was a problem hiding this comment.
yes, q1 behaves properly, but q2 blows up because nothing is returned
There was a problem hiding this comment.
yeah your version is safer, is fine.
There was a problem hiding this comment.
but in the new way you can still have concurrent insert/select no? the flatmap is not a tx boundary or is it?
There was a problem hiding this comment.
(if it is, then it explains it, otherwise you might still have a problem?)
There was a problem hiding this comment.
ah ok by default that is autocommit per statement
There was a problem hiding this comment.
the flatmap is not a tx boundary
it is; it's separate txs (storage.query twice, as opposed to DBIO composition)
There was a problem hiding this comment.
ok cool thanks I get it
| metrics.UpdateHistory.assignments.mark() | ||
| sqlu""" | ||
| for { | ||
| _ <- DBIO.from(internTemplateId(templateId)) |
There was a problem hiding this comment.
this is wrapping the future: i.e., it's not transactional with the rest of the statements. That should be fine since 99.99% of the time we're using the cache anyway
|
|
||
| // This does not need to be transactional with the rest of the transactions in UpdateHistory | ||
| private def internTemplateId(identifier: Identifier)(implicit tc: TraceContext): Future[Unit] = { | ||
| // TODO (#6257): use the returned ids in the partitioned table |
There was a problem hiding this comment.
we can start to fill up the store now and use it later in the partitioned tables
from the scan pruning doc:
The dualWrite/readFromId rollout in the String Interning design covers only the legacy tables, which are dropped wholesale, so it is no longer needed.
| "fetchAllInternedStrings", | ||
| ) | ||
| .map { all => | ||
| if (all.size >= maxSize) { |
There was a problem hiding this comment.
why don't you just do a count(1) on interned_strings (or similar on metadata of postgres), and then compare so maxSize? Also, we do not necessarily need all strings in cache, this depends on access pattern, will this not just lead to unnecessary warnings?
There was a problem hiding this comment.
ah right, thanks lol
There was a problem hiding this comment.
actually from this i realize i'm missing the package name and choice name in the updatehistory intern call done
| participantId = mkParticipantId(this.getClass.getSimpleName), | ||
| updateStreamParty = dsoParty, | ||
| backfillingRequired = UpdateHistory.BackfillingRequirement.BackfillingNotRequired, | ||
| internedStringStore = InternedStringStore.createWithoutWarmup( |
There was a problem hiding this comment.
Are you doing withoutWarmup in tests just to speed up the tests? Any idea how long this takes in ScanApp with the warmup?
There was a problem hiding this comment.
Are you doing withoutWarmup in tests just to speed up the tests?
doesn't really matter, the DB will be empty there
Any idea how long this takes in ScanApp with the warmup?
it's a query fetching 0-1000 rows, that shouldn't be too long
There was a problem hiding this comment.
so we don't need the withoutWarmup version?
There was a problem hiding this comment.
I guess not, I can remove it
There was a problem hiding this comment.
not a huge deal, was just wondering
There was a problem hiding this comment.
it does have the annoyance that warmup returns a Future, whereas the other one can just return the cache. Will leave as-is unless you disagree
There was a problem hiding this comment.
is fine, leave as is
ray-roestenburg-da
left a comment
There was a problem hiding this comment.
Looks good, thanks!
| .query( | ||
| sql""" | ||
| insert into interned_strings (value) values ($value) | ||
| on conflict (value) do nothing returning id; |
There was a problem hiding this comment.
This might consume an entry from the auto-increment sequence on each read. We should still be fine for the next billion years before the bigint overflows.
| config.acsStoreDescriptorUserVersion, | ||
| config.txLogStoreDescriptorUserVersion, | ||
| ) | ||
| internedStringStore <- InternedStringStore.createAndWarmupCache( |
There was a problem hiding this comment.
Loading all interned strings from the database will delay application startup slightly, do you know by how much?
There was a problem hiding this comment.
same answer as in #7111 (comment), there will be <10k strings that should fit in the cache and be trivially fetchable from a single query
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
31f2df4 to
9f8259e
Compare

Fixes #7075