Semantics of `fdb_future_set_callback`

I am exploring using fdb_future_set_callback in my bindings.

I am unable fully to understand the behavior of how callbacks would work when prematurely destroyed. I found this comment from @ajbeamon from an earlier thread.

Assuming a scenario where, callback has not been executed. If I were to call fdb_future_destroy in application thread T1. Is it the case that

  1. After fdb_future_destroy returns in thread T1, the callback would not get executed in any threads.

    Given the above comment (which I might be misunderstanding), this is unlikely, but I want to confirm anyway. :slight_smile:

    Basically if I have the guarantee, callback will not get executed after fdb_future_destroy has been called, then I can deal with memory backing callback_parameter in T1 cleanly after fdb_future_destroy has been called.

  2. The above comment seems to hint (again, I could be wrong), that calling fdb_future_destroy will cause the callback to run either in T1 or the network thread.

    This approach seems to indicate a design where once fdb_future_set_callback has been called, we are guaranteed to get a callback irrespective of whether the future gets prematurely destroyed or successfully resolves.

    During normal execution, when the future resolves, the callback will get executed. However, if fdb_future_destroy gets called, before the callback has had a chance to get called, we would still get a callback.

    For most futures, fdb_transaction_destroy will implicitly call fdb_future_destroy hence trigger the callback, if it hasn’t already been triggered.

    However, in case of watch future, after the transaction has been committed, this link between fdb_transaction_destroy and fdb_future_destroy is severed. So, after the transaction has been committed, the only way to trigger the watch future callback would be if - fdb_future_destroy gets called, or if the watch future resolves.

Am I understanding the semantics of callback correctly? Please let me know if there are any other edge cases, that I might not be thinking about.

The above comment seems to hint (again, I could be wrong), that calling fdb_future_destroy will cause the callback to run either in T1 or the network thread.

Calling fdb_future_destroy on an uncompleted future should result in it being completed with an error, and you would get a callback for that. This callback comes from the network thread and could come at some point later after your destroy call returns. If the future is already completed, then destroying it wouldn’t trigger another callback.

This approach seems to indicate a design where once fdb_future_set_callback has been called, we are guaranteed to get a callback irrespective of whether the future gets prematurely destroyed or successfully resolves.

This is true if it completes normally or you destroy it, but if neither happens it may never get called.

For most futures, fdb_transaction_destroy will implicitly call fdb_future_destroy hence trigger the callback, if it hasn’t already been triggered.

Destroying a transaction doesn’t destroy the futures, but it does fail many types of operations that were performed on that transaction. For example, I believe if you destroy a transaction it would fail any outstanding read requests, and that would result in your read callbacks being called with an error. For watches, destroying the transaction doesn’t cancel the watch and so the future is left open.

Thanks @ajbeamon for the reply! :slight_smile: