Mark Payne created NIP-50:
-----------------------------

             Summary: Partial Component State Updates
                 Key: NIP-50
                 URL: https://issues.apache.org/jira/browse/NIP-50
             Project: NiFi Improvement Proposal
          Issue Type: Improvement
            Reporter: Mark Payne
            Assignee: Mark Payne


h2. Motivation

{{setState}} and {{replace}} replace the entire state map. To change one key, a 
component must get the map, copy it, change the key, and write the whole map 
back. That is more code than the change needs, and two writers doing it at the 
same time can drop each other's keys.

Many components store independent keys in one map (one per table, partition, or 
cursor) and often change only a few of them. A method that accepts just those 
keys is simpler to use. It also lets a state store persist only what changed, 
which can be cheaper when the map is large.

h2. Proposed Solution

Add one method to both {{ProcessSession}} and {{StateManager}}:

{code:java}
void patchState(Map<String, String> updatedState, Scope scope) throws 
IOException;
{code}

The map is a patch, not a full replacement:

* Present keys with a non-null value are created or overwritten.
* Present keys with a {{null}} value are removed. Removing a key that is not 
there is a no-op. An empty string is stored; it does not remove the key.
* Keys that are not in the map are left as they are.

If no state is stored yet ({{StateMap}} version {{-1}}), the call matches 
{{setState}} after {{null}} values are dropped.

A {{null}} map is not allowed. An empty map is a no-op: no write and no version 
change.

{{ProcessSession.patchState}} follows the same commit rules as {{setState}}: 
the patch is cached on the session, {{getState}} in that session sees it, and 
it is published on commit only if it is still the latest remote state. Rollback 
discards it. A second {{patchState}} in the same session applies on top of the 
first cached result.

A default implementation is provided on both interfaces. Existing 
{{StateManager}} and {{ProcessSession}} implementations stay source-compatible. 
The default gets the current state, copies it into a new {{HashMap}}, applies 
the patch, and calls {{replace}} until that succeeds:

{code}
StateMap current;
do {
    current = getState(scope);
    Map<String, String> updated = new HashMap<>(current.toMap());
    for (each key/value in updatedState) {
        if (value is null) {
            updated.remove(key);
        } else {
            updated.put(key, value);
        }
    }
} while (!replace(current, updated, scope));
{code}

On {{ProcessSession}}, {{replace}} is {{replaceState}}. {{getState}} and 
{{replaceState}} already see session-cached state, so the same loop honors 
commit and rollback.

h2. NiFi API Changes

New default methods on {{org.apache.nifi.processor.ProcessSession}} and 
{{org.apache.nifi.components.state.StateManager}}, using the loop above.

{{StateTooLargeException}} still applies to the map after the patch is applied.

Backward compatible: additive default methods only.

h2. Voting Period

This NIP is proposed with a 24-hour lazy consensus voting period.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to