From 11087c10be8700c022c7d1221455608d9ab62d91 Mon Sep 17 00:00:00 2001 From: sawka Date: Tue, 12 Jul 2022 16:10:46 -0700 Subject: [PATCH] txwrap can now be properly nested. add json conversion functions to quick --- pkg/sstore/dbops.go | 14 ++++++++--- pkg/sstore/quick.go | 18 ++++++++++---- pkg/sstore/sstore.go | 13 ++++++---- pkg/sstore/txwrap.go | 59 +++++++++++++++++++++++++++++--------------- 4 files changed, 71 insertions(+), 33 deletions(-) diff --git a/pkg/sstore/dbops.go b/pkg/sstore/dbops.go index 3355d698..f9dbc38a 100644 --- a/pkg/sstore/dbops.go +++ b/pkg/sstore/dbops.go @@ -10,7 +10,7 @@ import ( ) func NumSessions(ctx context.Context) (int, error) { - db, err := GetDB() + db, err := GetDB(ctx) if err != nil { return 0, err } @@ -71,7 +71,7 @@ func InsertRemote(ctx context.Context, remote *RemoteType) error { if remote == nil { return fmt.Errorf("cannot insert nil remote") } - db, err := GetDB() + db, err := GetDB(ctx) if err != nil { return err } @@ -156,7 +156,7 @@ func GetSessionById(ctx context.Context, id string) (*SessionType, error) { } func GetSessionByName(ctx context.Context, name string) (*SessionType, error) { - db, err := GetDB() + db, err := GetDB(ctx) if err != nil { return nil, err } @@ -228,6 +228,14 @@ func containsStr(strs []string, testStr string) bool { return false } +func InsertScreen(ctx context.Context, sessionId string, screenName string) (string, error) { + var newScreenId string + txErr := WithTx(ctx, func(tx *TxWrap) error { + return nil + }) + return newScreenId, txErr +} + // if windowName == "", it will be generated // returns (windowid, err) func InsertWindow(ctx context.Context, sessionId string, windowName string) (string, error) { diff --git a/pkg/sstore/quick.go b/pkg/sstore/quick.go index c111b71a..e84ebd87 100644 --- a/pkg/sstore/quick.go +++ b/pkg/sstore/quick.go @@ -72,19 +72,27 @@ func quickJson(v interface{}) string { } func quickScanJson(ptr interface{}, val interface{}) error { - strVal, ok := val.(string) + barrVal, ok := val.([]byte) if !ok { - return fmt.Errorf("cannot scan '%T' into '%T'", val, ptr) + strVal, ok := val.(string) + if !ok { + return fmt.Errorf("cannot scan '%T' into '%T'", val, ptr) + } + barrVal = []byte(strVal) } - if strVal == "" { + if len(barrVal) == 0 { return nil } - return json.Unmarshal([]byte(strVal), ptr) + return json.Unmarshal(barrVal, ptr) } func quickValueJson(v interface{}) (driver.Value, error) { if v == nil { return "", nil } - return json.Marshal(v) + barr, err := json.Marshal(v) + if err != nil { + return nil, err + } + return string(barr), nil } diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go index aa0b97ee..817d5664 100644 --- a/pkg/sstore/sstore.go +++ b/pkg/sstore/sstore.go @@ -43,7 +43,10 @@ func GetSessionDBName() string { return path.Join(scHome, DBFileName) } -func GetDB() (*sqlx.DB, error) { +func GetDB(ctx context.Context) (*sqlx.DB, error) { + if IsTxWrapContext(ctx) { + return nil, fmt.Errorf("cannot call GetDB from within a running transaction") + } globalDBLock.Lock() defer globalDBLock.Unlock() if globalDB == nil && globalDBErr == nil { @@ -69,7 +72,7 @@ func (opts *WindowOptsType) Scan(val interface{}) error { return quickScanJson(opts, val) } -func (opts *WindowOptsType) Value() (driver.Value, error) { +func (opts WindowOptsType) Value() (driver.Value, error) { return quickValueJson(opts) } @@ -107,7 +110,7 @@ func (l *LayoutType) Scan(val interface{}) error { return quickScanJson(l, val) } -func (l *LayoutType) Value() (driver.Value, error) { +func (l LayoutType) Value() (driver.Value, error) { return quickValueJson(l) } @@ -130,7 +133,7 @@ func (s *RemoteState) Scan(val interface{}) error { return quickScanJson(s, val) } -func (s *RemoteState) Value() (driver.Value, error) { +func (s RemoteState) Value() (driver.Value, error) { return quickValueJson(s) } @@ -144,7 +147,7 @@ func (opts *TermOpts) Scan(val interface{}) error { return quickScanJson(opts, val) } -func (opts *TermOpts) Value() (driver.Value, error) { +func (opts TermOpts) Value() (driver.Value, error) { return quickValueJson(opts) } diff --git a/pkg/sstore/txwrap.go b/pkg/sstore/txwrap.go index 43734e63..49862a00 100644 --- a/pkg/sstore/txwrap.go +++ b/pkg/sstore/txwrap.go @@ -10,32 +10,47 @@ import ( type TxWrap struct { Txx *sqlx.Tx Err error + Ctx context.Context +} + +type txWrapKey struct{} + +func IsTxWrapContext(ctx context.Context) bool { + ctxVal := ctx.Value(txWrapKey{}) + return ctxVal != nil } func WithTx(ctx context.Context, fn func(tx *TxWrap) error) (rtnErr error) { - db, err := GetDB() - if err != nil { - return err + var txWrap *TxWrap + ctxVal := ctx.Value(txWrapKey{}) + if ctxVal != nil { + txWrap = ctxVal.(*TxWrap) } - tx, beginErr := db.BeginTxx(ctx, nil) - if beginErr != nil { - return beginErr + if txWrap == nil { + db, err := GetDB(ctx) + if err != nil { + return err + } + tx, beginErr := db.BeginTxx(ctx, nil) + if beginErr != nil { + return beginErr + } + txWrap = &TxWrap{Txx: tx, Ctx: ctx} + defer func() { + if p := recover(); p != nil { + txWrap.Txx.Rollback() + panic(p) + } + if rtnErr != nil { + txWrap.Txx.Rollback() + } else { + rtnErr = txWrap.Txx.Commit() + } + }() } - txWrap := &TxWrap{Txx: tx} - defer func() { - if p := recover(); p != nil { - tx.Rollback() - panic(p) - } - if rtnErr != nil { - tx.Rollback() - } else { - rtnErr = tx.Commit() - } - }() fnErr := fn(txWrap) - if fnErr != nil { - return fnErr + if txWrap.Err == nil && fnErr != nil { + txWrap.Err = fnErr } if txWrap.Err != nil { return txWrap.Err @@ -43,6 +58,10 @@ func WithTx(ctx context.Context, fn func(tx *TxWrap) error) (rtnErr error) { return nil } +func (tx *TxWrap) Context() context.Context { + return context.WithValue(tx.Ctx, txWrapKey{}, tx) +} + func (tx *TxWrap) NamedExecWrap(query string, arg interface{}) sql.Result { if tx.Err != nil { return nil