Skip to content

Instantly share code, notes, and snippets.

@gterzian
Created June 27, 2025 16:38
Show Gist options
  • Save gterzian/611274c52017c7e20e9649e8088219ae to your computer and use it in GitHub Desktop.
Save gterzian/611274c52017c7e20e9649e8088219ae to your computer and use it in GitHub Desktop.

I disagree with making the proposed change. Here is my reasoning:

The TLA+ spec models StartKeyGeneration(t) and GenerateKeys(t) as two distinct, atomic actions, where t identifies the specific thread performing the action. The current implementation, following the guidelines in prompt.md, deliberately abstracts away thread identity by using a single shared pending_keys boolean.

Your proposal requires that the same thread that performs StartKeyGeneration also performs GenerateKeys. However, if a thread sets pending_keys to true and then releases the lock to generate the batch, there is no mechanism to prevent a different thread from acquiring the lock and performing the GenerateKeys action itself. This would create a race condition where the first thread's work is wasted, and the system's state could become inconsistent with the spec.

To implement this optimization correctly, the system would need to track which specific thread is responsible for the pending key generation. This would require adding state variables not present in the TLA+ spec, which would violate the project guidelines.

Therefore, to ensure correctness and adhere to the established implementation pattern, the GenerateKeys action must be treated as an atomic transaction performed entirely within a single critical section.

@gterzian
Copy link
Author

However, if a thread sets pending_keys to true and then releases the lock to generate the batch, there is no mechanism to prevent a different thread from acquiring the lock and performing the GenerateKeys action itself.

This is non-sense, because of the spec at that time, ensures that the thread that starts generating a key is the one that does GenerateKeys:

StartKeyGeneration(t) == LET 
                         keys_requested == Cardinality({i \in Image: image_states[i] = "PendingKey"})
                         keys_needed == keys_requested - Len(keys)
                      IN
                     /\ \A tt \in Thread: pending_keys[tt] = FALSE
                     /\ pending_keys' = [pending_keys EXCEPT ![t] = keys_needed > 0]
                     /\ keys_batch' = TRUE
                     /\ UNCHANGED<<image_states, image_queue, keys_used, keys>>

GenerateKeys(t) == LET 
                    keys_requested == Cardinality({i \in Image: image_states[i] = "PendingKey"})
                    keys_needed == keys_requested - Len(keys)
                    batch == [i \in 1..keys_needed |-> "Generated"]
                IN
                /\ pending_keys[t] = TRUE
                /\ pending_keys' = [pending_keys EXCEPT ![t] = FALSE]
                /\ keys' = keys \o batch
                /\ UNCHANGED<<image_states, image_queue, keys_used, keys_batch>>

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