What are these key-value store semantics called? - publish-subscribe

Imagine a simple key-value server that allows the following verbs:
PUT key value - Sets the value of key to value
GET key - Gets the value of the key if it set, or indicates it is missing
WAIT key timeout - If the value of the key is set, get it immediately. Otherwise, block/wait until somebody else PUTs the key, returning as quickly as possible. If the timeout is reached, indicate failure.
These semantics are somewhat similar to Futures and Promises in various local execution environments, but in a distributed environment, I'm imagining it is typically accomplished with some combination of a messaging protocol and a key-value store.
I am wondering if anybody is either:
Aware of a good name for these semantics so I can start googling
Aware of a tool that offers this out of the box

Still not sure what the semantics are called -- but this is accomplishable using redis blocking.
Using blocking pop/pushes with one-element lists, we can implement the GETs as follows:
BRPOPLPUSH q q 0
If the list already exists, it will return the value immediately, and then just add it back to the list. If it doesn't it'll block until a value is added (or you can set a timeout using the last arg).
To set a value, you can just push to the list.
LPUSH q 1
If you want to ensure true SET semantics, you might prefer a transaction
MULTI
DEL q
LPUSH q 1
EXEC

Related

Clarify "the order of execution for the subtractor and adder is not defined"

The Streams DSL documentation includes a caveat about using the aggregate method to transform a KGroupedTable → KTable, as follows (emphasis mine):
When subsequent non-null values are received for a key (e.g., UPDATE), then (1) the subtractor is called with the old value as stored in the table and (2) the adder is called with the new value of the input record that was just received. The order of execution for the subtractor and adder is not defined.
My interpretation of that last line implies that one of three things can happen:
subtractor can be called before adder
adder can be called before subtractor
adder and subtractor could be called at the same time
Here is the question I'm looking to get answered:
Are all 3 scenarios above actually possible when using the aggregate method on a KGroupedTable?
Or am I misinterpreting the documentation? For my use-case (detailed below), it would be ideal if the subtractor was always be called before the adder.
Why is this question important?
If the adder and subtractor are non-commutative operations and the order in which they are executed can vary, you can end up with different results depending on the order of execution of adder and subtractor. An example of a useful non-commutative operation would be something like if we’re aggregating records into a Set:
.aggregate[Set[Animal]](Set.empty)(
adder = (zooKey, animalValue, setOfAnimals) => setOfAnimals + animalValue,
subtractor = (zooKey, animalValue, setOfAnimals) => setOfAnimals - animalValue
)
In this example, for duplicated events, if the adder is called before the subtractor you would end up removing the value entirely from the set (which would be problematic for most use-cases I imagine).
Why am I doubting the documentation (assuming my interpretation of it is correct)?
Seems like an unusual design choice
When I've run unit tests (using TopologyTestDriver and
EmbeddedKafka), I always see the subtractor is called before the
adder. Unfortunately, if there is some kind of race condition
involved, it's entirely possible that I would never hit the other
scenarios.
I did try looking into the kafka-streams codebase as well. The KTableProcessorSupplier that calls the user-supplied adder/subtracter functions appears to be this one: https://github.com/apache/kafka/blob/18547633697a29b690a8fb0c24e2f0289ecf8eeb/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KTableAggregate.java#L81 and on line 92, you can even see a comment saying "first try to remove the old value". Seems like this would answer my question definitively right? Unfortunately, in my own testing, what I saw was that the process function itself is called twice; first with a Change<V> value that includes only the old value and then the process function is called again with a Change<V> value that includes only the new value. Unfortunately, I haven't been able to dig deep enough to find the internal code that is generating the old value record and the new value record (upon receiving an update) to determine if it actually produces those records in that order.
The order is hard-coded (ie, no race condition), but there is no guarantee that the order won't change in future releases without notice (ie, it's not a public contract and no KIP is needed to change it). I guess there would be a Jira about it... But as a matter of fact, it does not really matter (detail below).
For the three scenarios you mentioned, the 3rd one cannot happen though: Aggregators are execute in a single thread (per shard) and thus either the adder or subtractor is called first.
first with a Change value that includes only
the old value and then the process function is called again with a Change
value that includes only the new value.
In general, both records might be processed by different threads and thus it's not possible to send only one record. It's just that the TTD simulates a single threaded execution thus both records always end up in the same processor.
Cf TopologyTestDriver sending incorrect message on KTable aggregations
However, the order actually only matters if both records really end up in the same processor (if the grouping key did not change during the upstream update).
Furthermore, the order actually depends not on the downstream aggregate implementation, but on the order of writes into the repartitions topic of the groupBy() and with multiple parallel upstream processor, those writes are interleaved anyway. Thus, in general, you should think of the "add" and "subtract" part as independent entities and not make any assumption about their order (also, even if the key did not change, both records might be interleaved by other records...)
The only guarantee provided is (given that you configured the producer correctly to avoid re-ordering during send()), that if the grouping key does not change, the send of the old and new value will not be re-ordered relative to each other. The order of the send is hard-coded in the upstream processor though:
https://github.com/apache/kafka/blob/trunk/streams/src/main/java/org/apache/kafka/streams/kstream/internals/KTableRepartitionMap.java#L93-L99
Thus, the order of the downstream aggregate processor is actually meaningless.

Firestore Increment - Cloud Function Invoked Twice

With Firestore Increment, what happens if you're using it in a Cloud Function and the Cloud Function is accidentally invoked twice?
To make sure that your function behaves correctly on retried execution attempts, you should make it idempotent by implementing it so that an event results in the desired results (and side effects) even if it is delivered multiple times.
E.g. the function is trying to increment a document field by 1
document("post/Post_ID_1").
updateData(["likes" : FieldValue.increment(1)])
So while Increment may be atomic it's not idempotent? If we want to make our counters idempotent we still need to use a transaction and keep track of who was the last person to like the post?
It will increment once for each invocation of the function. If that's not acceptable, you will need to write some code to figure out if any subsequent invocations are valid for your case.
There are many strategies to implement this, and it's up to you to choose one that suits your needs. The usual strategy is to use the event ID in the context object passed to your function to determine if that event has been successfully processed in the past. Maybe this involves storing that record in another document, in Redis, or somewhere that persists long enough for duplicates to be prevented (an hour should be OK).

How do I model a queue on top of a key-value store efficiently?

Supposed I have a key-value database, and I need to build a queue on top of it. How could I achieve this without getting a bad performance?
One idea might be to store the queue inside an array, and simply store the array using a fixed key. This is a quite simple implementation, but is very slow, as for every read or write access the complete array must be loaded / saved.
I could also implement a linked list, with random keys, and there is one fixed key which acts as starting point to element 1. Depending on if I prefer a fast read or a fast write access, I could let point the fixed element to the first or the last entry in the queue (so I have to travel it forward / backward).
Or, to proceed with that - I could also have two fixed pointers: One for the first, on for the last item.
Any other suggestions on how to do this effectively?
Initially, key-value structure is extremely similar to the original memory storage where the physical address in computer memory plays as the key. So any type of data structure could be modeled upon key-value storage surely, including linked list.
Originally, a linked list is a list of nodes including the index information of previous node or following node. Then the node it self should also be viewed as a sub key-value structure. With additional prefix to the key, the information in the node could be separately stored in a flat table of key-value pairs.
To proceed with that, special suffix to the key could also make it possible to get rid of redundant pointer information. This pretend list might look something like this:
pilot-last-index: 5
pilot-0: Rei Ayanami
pilot-1: Shinji Ikari
pilot-2: Soryu Asuka Langley
pilot-3: Touji Suzuhara
pilot-5: Makinami Mari
The corresponding algrithm is also imaginable, I think. If you could have a daemon thread for manipulation these keys, pilot-5 could be renamed as pilot-4 in the above example. Even though, it is not allowed to have additional thread in some special situation, the result of the queue it self is not affected. Just some overhead would exist for the break point in sequence.
However which of the two above should be applied is the problem of balance between the cost of storage space or the overhead of CPU time.
The thread safe is exactly a problem however an ancient problem. Just like the class implementing the interface of ConcurrentMap in JDK, Atomic operation on key-value data is also provided perfectly. There are similar methods featured in some key-value middleware, like memcached, as well, which could make you update key or value separately and thread safely. However these implementation is the algrithm problem rather than the key-value structure it self.
I think it depends on the kind of queue you want to implement, and no solution will be perfect because a key-value store is not the right data structure for this kind of task. There will be always some kind of hack involved.
For a simple first in first out queue you could use a few kev-value stores like the folliwing:
{
oldestIndex:5,
newestIndex:10
}
In this example there would be 6 items in the Queue (5,6,7,8,9,10). Item 0 to 4 are already done whereas there is no Item 11 or so for now. The producer worker would increment newestIndex and save his item under the key 11. The consumer takes the item under the key 5 and increments oldestIndex.
Note that this approach can lead to problems if you have multiple consumer/producers and if the queue is never empty so you cant reset the index.
But the multithreading problem is also true for linked lists etc.

How can I get the index of an item in an IOrderedQueryable?

Background:
I'm designing a list-like control (WinForms) that's backed by a DbSet. A chief requirement is that it doesn't load the entire list into local memory. I'm using a DataGridView in virtual mode as the underlying UI. I'm planning to implement the CellValueNeeded function as orderedQueryable.ElementAt(n).
Problem:
I need to allow the control's consumer to get/set the currently-selected value, by value rather than by index. Getting is easy--it's the same as the CellValueNeeded operation--but setting is harder: it requires me to get the index of a given element. There's not a built-in orderedQueryable.FirstIndexOf(value) operation, and although I could theoretically fake it with some sort of orderedQueryable.SkipWhile shenanigans where the expression has a side-effect, in practice the DbSet's query provider probably doesn't support doing that.
Questions:
Is there an efficient way to get the index of a particular value within an IOrderedQueryable? How?
(If this approach turns out to be untenable, I'd settle for suggestions on how I might restructure the problem to make it solvable.)
Side notes:
Elements can be inserted and removed from the list, in which case the old indices will be invalid--that's acceptable, since they're never exposed to the consumer. It's an error for the consumer to attempt to select an item that isn't actually in the list, and actually the consumer would have gotten the item from the list in the first place (although perhaps the indices have changed since then).

Atomic GETSET on a hash in Redis

I'm going to be storing a hit counter for a number of URLs in Redis. I'm planning on using a hash because that seems to make sense. It also has an atomic increment function which is critical to my use case.
Every so often, I'm going to aggregate the hit count per URL into another data store. For this purpose, I'd like to get the hit count and reset it back to zero. I can't seem to find an operation like GETSET that works on hashes. If I record a hit between getting the hit count and resetting it to zero, it will get lost without some kind of atomic operation.
Am I missing something? One alternative that occurred to me would be to hash the URL in my client (python) code and use the string commands, but that seems like a bit of a hack when Redis provides a hash itself.
Try to look at redis transactions docs, namely the combination of WATCH and MULTI commands:
WATCHed keys are monitored in order to detect changes against them. If
at least one watched key is modified before the EXEC command, the
whole transaction aborts, and EXEC returns a Null multi-bulk reply to
notify that the transaction failed.
...
So what is WATCH really about?
It is a command that will make the EXEC conditional: we are asking
Redis to perform the transaction only if no other client modified any
of the WATCHed keys. Otherwise the transaction is not entered at all.