-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: DB transactions context #2513
refactor: DB transactions context #2513
Conversation
db/session/session.go
Outdated
type contextKey string | ||
|
||
const ( | ||
TxnContextKey = contextKey("txn") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: To avoid allocation on the key, you can simply use
type TxnContextKey struct{}
db/collection.go
Outdated
if err != nil { | ||
return nil, err | ||
} | ||
|
||
txn := mustGetContextTxn(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: It's a little weird that whe need to extract the txn
from the context and the next function call passes the context and the transaction.
question: Why not leave it to the function that needs the txn
to get it from the context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone had a preference for this in the standup discussion. If a function requires a transaction it should remain as a parameter and not come from context.
db/context.go
Outdated
// | ||
// If a transactions exists on the context it will be made explicit, | ||
// otherwise a new implicit transaction will be created. | ||
func ensureContextTxn(ctx context.Context, db transactionDB, readOnly bool) (context.Context, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: There is a lot of ensureContextTxn
followed by mustGetContextTxn
. To avoid having to type cast everytime, I would suggest returning datastore.Txn
here.
func ensureContextTxn(ctx context.Context, db transactionDB, readOnly bool) (context.Context, datastore.Txn, error)
db/store.go
Outdated
|
||
var _ client.Store = (*store)(nil) | ||
|
||
type store struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Can you explain why you prefer wrapping the db
instead of using it directly for the methods bellow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. There's no need for a separate struct anymore. Would you prefer these functions remain in store.go
or would it be better to move them into db.go
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
store.go
is fine with me. We could even add documentation at the top saying that the fonction within implement the client.Store
interface for db
.
http/handler_ccip.go
Outdated
@@ -35,7 +35,7 @@ type CCIPResponse struct { | |||
|
|||
// ExecCCIP handles GraphQL over Cross Chain Interoperability Protocol requests. | |||
func (c *ccipHandler) ExecCCIP(rw http.ResponseWriter, req *http.Request) { | |||
store := req.Context().Value(storeContextKey).(client.Store) | |||
db := req.Context().Value(dbContextKey).(client.DB) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: There is nothing wrong with keeping the more restrictive type casting of client.Store
since that is really what is needed here.
net/server.go
Outdated
@@ -349,15 +353,14 @@ func (s *server) syncIndexedDocs( | |||
ctx context.Context, | |||
col client.Collection, | |||
docID client.DocID, | |||
txn datastore.Txn, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: Remove unused param.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the changes. I'll just wait for the comments to be resolved before approving.
I'm wondering if we should remove the txn
from function params when the context already holds it. Probably out of scope for this PR but could be done shortly after.
Edit: Will bring it up in the standup.
I'm not a huge fan of this PR, not sure if its the specific implementation or the general concept (txn via context). This was my concern when discussing it in the ACP discord thread regarding the use of txn via the context making the depedency more opaque. It can make following the call stack of a given transaction harder to reason about and easier to mess up. Heres an example in the It has the following function signature It uses the Then makes a call to the a public function which doesn't use the txn It is not 100% clear the txn scope the last call is using, since the calling function ( Before, the last line was -- Theres a possible solution here: in fact after reviewing this, and the existing (develop) implementation, there is actually a bug where some call paths don't respect transaction scopes correctly because of the implicit Oddly enough, this PR actually fixes that without intending to because of the shared context. Perhaps my issue isn't necessarily with the transaction context propagation, but the inconsistency we have between implicit and explicit transactions and how they are handled, both on the Happy to chat more during the dev call today (cc @nasdf @fredcarle ) |
|
||
// SetContextTxn returns a new context with the txn value set. | ||
func SetContextTxn(ctx context.Context, txn datastore.Txn) context.Context { | ||
return context.WithValue(ctx, txnContextKey{}, txn) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo: I think we need to check here if there is already an existing transaction in the context. I there is one, current code will override it allowing potentially to leak the old transaction that was not discarded yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ensureContextTxn
makes sure we don't overwrite an existing transaction. There is a case within net/server.go
where we need the functionality to overwrite the transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if having ensureContextTxn
is enough in this case. SetContextTxn
is a public method and can be called from anywhere. If ensureContextTxn
is required to call before calling this one, why not to make it part of it? Otherwise I see no link between the two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not seeing the issue here. The lifetime of the transaction is managed from the caller. If the caller overwrites a transaction and forgets to discard it, then the bug is in the caller's code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the intention is to put this responsibility on the caller's side, it's fine, but then it needs to be documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the function docs to be more clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Relevant issue(s)
Resolves #2512
Resolves #2516
Description
This PR moves the db transactions to the context.
Notable Changes:
txn_db.go
tostore.go
replacedexplicitTxnDB
andimplicitTxnDb
withstore
addeddb/session.go
to simplify setting contextdb/context.go
to manage context valuesTasks
How has this been tested?
make test
Specify the platform(s) on which this was tested: