本文整理汇总了Golang中github.com/cockroachdb/cockroach/roachpb.NewErrorWithTxn函数的典型用法代码示例。如果您正苦于以下问题:Golang NewErrorWithTxn函数的具体用法?Golang NewErrorWithTxn怎么用?Golang NewErrorWithTxn使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了NewErrorWithTxn函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: maybeRejectClientLocked
// maybeRejectClientLocked checks whether the (transactional) request is in a
// state that prevents it from continuing, such as the coordinator having
// considered the client abandoned, or a heartbeat having reported an error.
func (tc *TxnCoordSender) maybeRejectClientLocked(
ctx context.Context,
txn roachpb.Transaction,
) *roachpb.Error {
if !txn.Writing {
return nil
}
txnMeta, ok := tc.txns[*txn.ID]
// Check whether the transaction is still tracked and has a chance of
// completing. It's possible that the coordinator learns about the
// transaction having terminated from a heartbeat, and GC queue correctness
// (along with common sense) mandates that we don't let the client
// continue.
switch {
case !ok:
// TODO(spencerkimball): Could add coordinator node ID to the
// transaction session so that we can definitively return the right
// error between these possible errors. Or update the code to make an
// educated guess based on the incoming transaction timestamp.
return roachpb.NewError(errNoState)
case txnMeta.txn.Status == roachpb.ABORTED:
txn := txnMeta.txn.Clone()
tc.cleanupTxnLocked(ctx, txn)
return roachpb.NewErrorWithTxn(roachpb.NewTransactionAbortedError(),
&txn)
case txnMeta.txn.Status == roachpb.COMMITTED:
txn := txnMeta.txn.Clone()
tc.cleanupTxnLocked(ctx, txn)
return roachpb.NewErrorWithTxn(roachpb.NewTransactionStatusError(
"transaction is already committed"), &txn)
default:
return nil
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:38,代码来源:txn_coord_sender.go
示例2: TestEndWriteRestartReadOnlyTransaction
// TestEndWriteRestartReadOnlyTransaction verifies that if
// a transaction writes, then restarts and turns read-only,
// an explicit EndTransaction call is still sent if retry-
// able didn't, regardless of whether there is an error
// or not.
func TestEndWriteRestartReadOnlyTransaction(t *testing.T) {
defer leaktest.AfterTest(t)()
for _, success := range []bool{true, false} {
expCalls := []roachpb.Method{roachpb.BeginTransaction, roachpb.Put, roachpb.EndTransaction}
var calls []roachpb.Method
db := NewDB(newTestSender(func(ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) {
calls = append(calls, ba.Methods()...)
return ba.CreateReply(), nil
}, nil))
ok := false
if err := db.Txn(context.TODO(), func(txn *Txn) error {
if !ok {
if err := txn.Put("consider", "phlebas"); err != nil {
t.Fatal(err)
}
ok = true
// Return an immediate txn retry error. We need to go through the pErr
// and back to get a RetryableTxnError.
return roachpb.NewErrorWithTxn(roachpb.NewTransactionRetryError(), &txn.Proto).GoError()
}
if !success {
return errors.New("aborting on purpose")
}
return nil
}); err == nil != success {
t.Errorf("expected error: %t, got error: %v", !success, err)
}
if !reflect.DeepEqual(expCalls, calls) {
t.Fatalf("expected %v, got %v", expCalls, calls)
}
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:37,代码来源:txn_test.go
示例3: TestWrongTxnRetry
// Tests that a retryable error for an inner txn doesn't cause the outer txn to
// be retried.
func TestWrongTxnRetry(t *testing.T) {
defer leaktest.AfterTest(t)()
db := NewDB(newTestSender(nil, nil))
var retries int
txnClosure := func(outerTxn *Txn) error {
log.Infof(context.Background(), "outer retry")
retries++
// Ensure the KV transaction is created.
if err := outerTxn.Put("a", "b"); err != nil {
t.Fatal(err)
}
var execOpt TxnExecOptions
execOpt.AutoRetry = false
err := outerTxn.Exec(
execOpt,
func(innerTxn *Txn, opt *TxnExecOptions) error {
// Ensure the KV transaction is created.
if err := innerTxn.Put("x", "y"); err != nil {
t.Fatal(err)
}
return roachpb.NewErrorWithTxn(&roachpb.TransactionPushError{
PusheeTxn: outerTxn.Proto}, &innerTxn.Proto).GoError()
})
return err
}
if err := db.Txn(context.TODO(), txnClosure); !testutils.IsError(err, "failed to push") {
t.Fatal(err)
}
if retries != 1 {
t.Fatalf("unexpected retries: %d", retries)
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:36,代码来源:txn_test.go
示例4: TestNonRetryableErrorFromCommit
// TestNonRetryableError verifies that a non-retryable error from the
// execution of EndTransactionRequests is propagated to the client.
func TestNonRetryableErrorFromCommit(t *testing.T) {
defer leaktest.AfterTest(t)()
params, cmdFilters := createTestServerParams()
s, sqlDB, _ := serverutils.StartServer(t, params)
defer s.Stopper().Stop()
hitError := false
cleanupFilter := cmdFilters.AppendFilter(
func(args storagebase.FilterArgs) *roachpb.Error {
if req, ok := args.Req.(*roachpb.EndTransactionRequest); ok {
if bytes.Contains(req.Key, []byte(keys.DescIDGenerator)) {
hitError = true
return roachpb.NewErrorWithTxn(fmt.Errorf("testError"), args.Hdr.Txn)
}
}
return nil
}, false)
defer cleanupFilter()
if _, err := sqlDB.Exec("CREATE DATABASE t;"); !testutils.IsError(err, "pq: testError") {
t.Errorf("unexpected error %v", err)
}
if !hitError {
t.Errorf("expected to hit error, but it didn't happen")
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:29,代码来源:txn_restart_test.go
示例5: TestNestedTransaction
// Verifies that an inner transaction in a nested transaction strips the transaction
// information in its error when propagating it to an other transaction.
func TestNestedTransaction(t *testing.T) {
defer leaktest.AfterTest(t)()
s, db := setup()
defer s.Stop()
pErr := db.Txn(func(txn1 *client.Txn) *roachpb.Error {
if pErr := txn1.Put("a", "1"); pErr != nil {
t.Fatalf("unexpected put error: %s", pErr)
}
iPErr := db.Txn(func(txn2 *client.Txn) *roachpb.Error {
txnProto := roachpb.NewTransaction("test", roachpb.Key("a"), 1, roachpb.SERIALIZABLE, roachpb.Timestamp{}, 0)
return roachpb.NewErrorWithTxn(util.Errorf("inner txn error"), txnProto)
})
if iPErr.GetTxn() != nil {
t.Errorf("error txn must be stripped: %s", iPErr)
}
return iPErr
})
if pErr == nil {
t.Fatal("unexpected success of txn")
}
if !testutils.IsPError(pErr, "inner txn error") {
t.Errorf("unexpected failure: %s", pErr)
}
}
开发者ID:bogdanbatog,项目名称:cockroach,代码行数:29,代码来源:db_test.go
示例6: TestNonRetryableError
// TestNonRetryableError verifies that a non-retryable error is propagated to the client.
func TestNonRetryableError(t *testing.T) {
defer leaktest.AfterTest(t)()
ctx, cmdFilters := createTestServerContext()
server, sqlDB, _ := setupWithContext(t, &ctx)
defer cleanup(server, sqlDB)
testKey := []byte("test_key")
hitError := false
cleanupFilter := cmdFilters.AppendFilter(
func(args storagebase.FilterArgs) *roachpb.Error {
if req, ok := args.Req.(*roachpb.ScanRequest); ok {
if bytes.Contains(req.Key, testKey) {
hitError = true
return roachpb.NewErrorWithTxn(fmt.Errorf("testError"), args.Hdr.Txn)
}
}
return nil
}, false)
defer cleanupFilter()
sqlDB.SetMaxOpenConns(1)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (k TEXT PRIMARY KEY, v TEXT);
INSERT INTO t.test (k, v) VALUES ('test_key', 'test_val');
SELECT * from t.test WHERE k = 'test_key';
`); !testutils.IsError(err, "pq: testError") {
t.Errorf("unexpected error %s", err)
}
if !hitError {
t.Errorf("expected to hit error, but it didn't happen")
}
}
开发者ID:mjibson,项目名称:cockroach,代码行数:35,代码来源:txn_restart_test.go
示例7: TestRunTransactionRetryOnErrors
// TestRunTransactionRetryOnErrors verifies that the transaction
// is retried on the correct errors.
func TestRunTransactionRetryOnErrors(t *testing.T) {
defer leaktest.AfterTest(t)()
testCases := []struct {
err error
retry bool // Expect retry?
}{
{roachpb.NewReadWithinUncertaintyIntervalError(hlc.ZeroTimestamp, hlc.ZeroTimestamp), true},
{&roachpb.TransactionAbortedError{}, true},
{&roachpb.TransactionPushError{}, true},
{&roachpb.TransactionRetryError{}, true},
{&roachpb.WriteTooOldError{}, true},
{&roachpb.RangeNotFoundError{}, false},
{&roachpb.RangeKeyMismatchError{}, false},
{&roachpb.TransactionStatusError{}, false},
}
for i, test := range testCases {
count := 0
dbCtx := DefaultDBContext()
dbCtx.TxnRetryOptions.InitialBackoff = 1 * time.Millisecond
db := NewDBWithContext(newTestSender(
func(ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) {
if _, ok := ba.GetArg(roachpb.Put); ok {
count++
if count == 1 {
return nil, roachpb.NewErrorWithTxn(test.err, ba.Txn)
}
}
return ba.CreateReply(), nil
}, nil), dbCtx)
err := db.Txn(context.TODO(), func(txn *Txn) error {
return txn.Put("a", "b")
})
if test.retry {
if count != 2 {
t.Errorf("%d: expected one retry; got %d", i, count-1)
}
if err != nil {
t.Errorf("%d: expected success on retry; got %s", i, err)
}
} else {
if count != 1 {
t.Errorf("%d: expected no retries; got %d", i, count)
}
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("%d: expected error of type %T; got %T", i, test.err, err)
}
}
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:53,代码来源:txn_test.go
示例8: TestAbortCountConflictingWrites
func TestAbortCountConflictingWrites(t *testing.T) {
defer leaktest.AfterTest(t)()
ctx, cmdFilters := createTestServerContext()
s, sqlDB, _ := setupWithContext(t, ctx)
defer cleanup(s, sqlDB)
if _, err := sqlDB.Exec("CREATE DATABASE db"); err != nil {
t.Fatal(err)
}
if _, err := sqlDB.Exec("CREATE TABLE db.t (k TEXT PRIMARY KEY, v TEXT)"); err != nil {
t.Fatal(err)
}
// Inject errors on the INSERT below.
restarted := false
cmdFilters.AppendFilter(func(args storageutils.FilterArgs) *roachpb.Error {
switch req := args.Req.(type) {
// SQL INSERT generates ConditionalPuts for unique indexes (such as the PK).
case *roachpb.ConditionalPutRequest:
if bytes.Contains(req.Value.RawBytes, []byte("marker")) && !restarted {
restarted = true
return roachpb.NewErrorWithTxn(
roachpb.NewTransactionAbortedError(), args.Hdr.Txn)
}
}
return nil
}, false)
txn, err := sqlDB.Begin()
if err != nil {
t.Fatal(err)
}
_, err = txn.Exec("INSERT INTO db.t VALUES ('key', 'marker')")
if !testutils.IsError(err, "aborted") {
t.Fatal(err)
}
if err = txn.Rollback(); err != nil {
t.Fatal(err)
}
checkCounterEQ(t, s, "txn.abort.count", 1)
checkCounterEQ(t, s, "txn.begin.count", 1)
checkCounterEQ(t, s, "txn.rollback.count", 0)
checkCounterEQ(t, s, "txn.commit.count", 0)
checkCounterEQ(t, s, "insert.count", 1)
}
开发者ID:petermattis,项目名称:cockroach,代码行数:48,代码来源:metric_test.go
示例9: TestTxnResetTxnOnAbort
// TestTxnResetTxnOnAbort verifies transaction is reset on abort.
func TestTxnResetTxnOnAbort(t *testing.T) {
defer leaktest.AfterTest(t)
db := newDB(newTestSender(func(ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) {
return nil, roachpb.NewErrorWithTxn(&roachpb.TransactionAbortedError{}, ba.Txn)
}, nil))
txn := NewTxn(*db)
_, pErr := txn.db.sender.Send(context.Background(), testPut())
if _, ok := pErr.GetDetail().(*roachpb.TransactionAbortedError); !ok {
t.Fatalf("expected TransactionAbortedError, got %v", pErr)
}
if txn.Proto.ID != nil {
t.Errorf("expected txn to be cleared")
}
}
开发者ID:steelglove,项目名称:cockroach,代码行数:17,代码来源:txn_test.go
示例10: TestTransactionKeyNotChangedInRestart
// TestTransactionKeyNotChangedInRestart verifies that if the transaction already has a key (we're
// in a restart), the key in the begin transaction request is not changed.
func TestTransactionKeyNotChangedInRestart(t *testing.T) {
defer leaktest.AfterTest(t)()
tries := 0
db := NewDB(newTestSender(nil, func(ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) {
var bt *roachpb.BeginTransactionRequest
if args, ok := ba.GetArg(roachpb.BeginTransaction); ok {
bt = args.(*roachpb.BeginTransactionRequest)
} else {
t.Fatal("failed to find a begin transaction request")
}
// In the first try, the transaction key is the key of the first write command. Before the
// second try, the transaction key is set to txnKey by the test sender. In the second try, the
// transaction key is txnKey.
var expectedKey roachpb.Key
if tries == 1 {
expectedKey = testKey
} else {
expectedKey = txnKey
}
if !bt.Key.Equal(expectedKey) {
t.Fatalf("expected transaction key %v, got %v", expectedKey, bt.Key)
}
return ba.CreateReply(), nil
}))
if err := db.Txn(context.TODO(), func(txn *Txn) error {
tries++
b := txn.NewBatch()
b.Put("a", "b")
if err := txn.Run(b); err != nil {
t.Fatal(err)
}
if tries == 1 {
return roachpb.NewErrorWithTxn(roachpb.NewTransactionRetryError(), &txn.Proto).GoError()
}
return nil
}); err != nil {
t.Errorf("unexpected error on commit: %s", err)
}
minimumTries := 2
if tries < minimumTries {
t.Errorf("expected try count >= %d, got %d", minimumTries, tries)
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:48,代码来源:txn_test.go
示例11: TestRollbackInRestartWait
// TestRollbackInRestartWait ensures that a ROLLBACK while the txn is in the
// RetryWait state works.
func TestRollbackInRestartWait(t *testing.T) {
defer leaktest.AfterTest(t)()
params, cmdFilters := createTestServerParams()
s, sqlDB, _ := serverutils.StartServer(t, params)
defer s.Stopper().Stop()
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (k TEXT PRIMARY KEY, v TEXT);
`); err != nil {
t.Fatal(err)
}
// Set up error injection that causes retries.
magicVals := createFilterVals(nil, nil)
magicVals.endTxnRestartCounts = map[string]int{
"boulanger": 1,
}
defer cmdFilters.AppendFilter(
func(args storagebase.FilterArgs) *roachpb.Error {
if err := injectErrors(args.Req, args.Hdr, magicVals); err != nil {
return roachpb.NewErrorWithTxn(err, args.Hdr.Txn)
}
return nil
}, false)()
tx, err := sqlDB.Begin()
if err != nil {
t.Fatal(err)
}
if _, err := tx.Exec("SAVEPOINT cockroach_restart"); err != nil {
t.Fatal(err)
}
if _, err := tx.Exec(
"INSERT INTO t.test (k, v) VALUES ('g', 'boulanger')"); err != nil {
t.Fatal(err)
}
if _, err := tx.Exec("RELEASE SAVEPOINT cockroach_restart"); err == nil {
t.Fatal("expected RELEASE to fail")
}
if err := tx.Rollback(); err != nil {
t.Fatal(err)
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:47,代码来源:txn_restart_test.go
示例12: TestNestedTransaction
// Verifies that a nested transaction returns an error if an inner txn
// propagates an error to an outer txn.
func TestNestedTransaction(t *testing.T) {
defer leaktest.AfterTest(t)()
s, db := setup()
defer s.Stop()
txnProto := roachpb.NewTransaction("test", roachpb.Key("a"), 1, roachpb.SERIALIZABLE, roachpb.Timestamp{}, 0)
pErr := db.Txn(func(txn1 *client.Txn) *roachpb.Error {
if pErr := txn1.Put("a", "1"); pErr != nil {
t.Fatalf("unexpected put error: %s", pErr)
}
return db.Txn(func(txn2 *client.Txn) *roachpb.Error {
return roachpb.NewErrorWithTxn(util.Errorf("err"), txnProto)
})
})
if pErr == nil {
t.Fatal("unexpected success of txn")
}
if !testutils.IsPError(pErr, "mismatching transaction record in the error") {
t.Errorf("unexpected failure: %s", pErr)
}
}
开发者ID:mrtracy,项目名称:cockroach,代码行数:23,代码来源:db_test.go
示例13: TestNonRetryableError
// TestNonRetryableError verifies that a non-retryable error is propagated to the client.
func TestNonRetryableError(t *testing.T) {
defer leaktest.AfterTest(t)()
params, cmdFilters := createTestServerParams()
s, sqlDB, _ := serverutils.StartServer(t, params)
defer s.Stopper().Stop()
testKey := []byte("test_key")
hitError := false
cleanupFilter := cmdFilters.AppendFilter(
func(args storagebase.FilterArgs) *roachpb.Error {
if req, ok := args.Req.(*roachpb.ScanRequest); ok {
if bytes.Contains(req.Key, testKey) {
hitError = true
return roachpb.NewErrorWithTxn(fmt.Errorf("testError"), args.Hdr.Txn)
}
}
return nil
}, false)
defer cleanupFilter()
// We need to do everything on one connection as we'll want to observe the
// connection state after a COMMIT.
sqlDB.SetMaxOpenConns(1)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (k TEXT PRIMARY KEY, v TEXT);
INSERT INTO t.test (k, v) VALUES ('test_key', 'test_val');
SELECT * from t.test WHERE k = 'test_key';
`); !testutils.IsError(err, "pq: testError") {
t.Errorf("unexpected error %v", err)
}
if !hitError {
t.Errorf("expected to hit error, but it didn't happen")
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:37,代码来源:txn_restart_test.go
示例14: TestGCQueueTransactionTable
//.........这里部分代码省略.........
status: roachpb.COMMITTED,
orig: gcTxnAndAC - 1,
newStatus: -1,
expResolve: true,
expAbortGC: true,
},
// Same as the previous one, but we've rigged things so that the intent
// resolution here will fail and consequently no GC is expected.
"g": {
status: roachpb.COMMITTED,
orig: gcTxnAndAC - 1,
newStatus: roachpb.COMMITTED,
failResolve: true,
expResolve: true,
expAbortGC: true,
},
}
resolved := map[string][]roachpb.Span{}
tc := testContext{}
tsc := TestStoreContext()
tsc.TestingKnobs.TestingCommandFilter =
func(filterArgs storagebase.FilterArgs) *roachpb.Error {
if resArgs, ok := filterArgs.Req.(*roachpb.ResolveIntentRequest); ok {
id := string(resArgs.IntentTxn.Key)
resolved[id] = append(resolved[id], roachpb.Span{
Key: resArgs.Key,
EndKey: resArgs.EndKey,
})
// We've special cased one test case. Note that the intent is still
// counted in `resolved`.
if testCases[id].failResolve {
return roachpb.NewErrorWithTxn(util.Errorf("boom"), filterArgs.Hdr.Txn)
}
}
return nil
}
tc.StartWithStoreContext(t, tsc)
defer tc.Stop()
tc.manualClock.Set(int64(now))
outsideKey := tc.rng.Desc().EndKey.Next().AsRawKey()
testIntents := []roachpb.Span{{Key: roachpb.Key("intent")}}
txns := map[string]roachpb.Transaction{}
for strKey, test := range testCases {
baseKey := roachpb.Key(strKey)
txnClock := hlc.NewClock(hlc.NewManualClock(int64(test.orig)).UnixNano)
txn := newTransaction("txn1", baseKey, 1, enginepb.SERIALIZABLE, txnClock)
txn.Status = test.status
txn.Intents = testIntents
if test.hb > 0 {
txn.LastHeartbeat = &hlc.Timestamp{WallTime: int64(test.hb)}
}
// Set a high Timestamp to make sure it does not matter. Only
// OrigTimestamp (and heartbeat) are used for GC decisions.
txn.Timestamp.Forward(hlc.MaxTimestamp)
txns[strKey] = *txn
for _, addrKey := range []roachpb.Key{baseKey, outsideKey} {
key := keys.TransactionKey(addrKey, txn.ID)
if err := engine.MVCCPutProto(context.Background(), tc.engine, nil, key, hlc.ZeroTimestamp, nil, txn); err != nil {
t.Fatal(err)
}
}
entry := roachpb.AbortCacheEntry{Key: txn.Key, Timestamp: txn.LastActive()}
开发者ID:csdigi,项目名称:cockroach,代码行数:67,代码来源:gc_queue_test.go
示例15: send
// send runs the specified calls synchronously in a single batch and
// returns any errors. If the transaction is read-only or has already
// been successfully committed or aborted, a potential trailing
// EndTransaction call is silently dropped, allowing the caller to
// always commit or clean-up explicitly even when that may not be
// required (or even erroneous). Returns (nil, nil) for an empty batch.
func (txn *Txn) send(ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) {
if txn.Proto.Status != roachpb.PENDING || txn.IsFinalized() {
return nil, roachpb.NewErrorf(
"attempting to use transaction with wrong status or finalized: %s", txn.Proto.Status)
}
// It doesn't make sense to use inconsistent reads in a transaction. However,
// we still need to accept it as a parameter for this to compile.
if ba.ReadConsistency != roachpb.CONSISTENT {
return nil, roachpb.NewErrorf("cannot use %s ReadConsistency in txn",
ba.ReadConsistency)
}
lastIndex := len(ba.Requests) - 1
if lastIndex < 0 {
return nil, nil
}
// firstWriteIndex is set to the index of the first command which is
// a transactional write. If != -1, this indicates an intention to
// write. This is in contrast to txn.Proto.Writing, which is set by
// the coordinator when the first intent has been created, and which
// lives for the life of the transaction.
firstWriteIndex := -1
var firstWriteKey roachpb.Key
for i, ru := range ba.Requests {
args := ru.GetInner()
if i < lastIndex {
if _, ok := args.(*roachpb.EndTransactionRequest); ok {
return nil, roachpb.NewErrorf("%s sent as non-terminal call", args.Method())
}
}
if roachpb.IsTransactionWrite(args) && firstWriteIndex == -1 {
firstWriteKey = args.Header().Key
firstWriteIndex = i
}
}
haveTxnWrite := firstWriteIndex != -1
endTxnRequest, haveEndTxn := ba.Requests[lastIndex].GetInner().(*roachpb.EndTransactionRequest)
needBeginTxn := !txn.Proto.Writing && haveTxnWrite
needEndTxn := txn.Proto.Writing || haveTxnWrite
elideEndTxn := haveEndTxn && !needEndTxn
// If we're not yet writing in this txn, but intend to, insert a
// begin transaction request before the first write command.
if needBeginTxn {
// If the transaction already has a key (we're in a restart), make
// sure we set the key in the begin transaction request to the original.
bt := &roachpb.BeginTransactionRequest{
Span: roachpb.Span{
Key: firstWriteKey,
},
}
if txn.Proto.Key != nil {
bt.Key = txn.Proto.Key
}
// Inject the new request before position firstWriteIndex, taking
// care to avoid unnecessary allocations.
oldRequests := ba.Requests
ba.Requests = make([]roachpb.RequestUnion, len(ba.Requests)+1)
copy(ba.Requests, oldRequests[:firstWriteIndex])
ba.Requests[firstWriteIndex].MustSetInner(bt)
copy(ba.Requests[firstWriteIndex+1:], oldRequests[firstWriteIndex:])
}
if elideEndTxn {
ba.Requests = ba.Requests[:lastIndex]
}
br, pErr := txn.db.send(ba)
if elideEndTxn && pErr == nil {
// Check that read only transactions do not violate their deadline. This can NOT
// happen since the txn deadline is normally updated when it is about to expire
// or expired. We will just keep the code for safety (see TestReacquireLeaseOnRestart).
if endTxnRequest.Deadline != nil {
if endTxnRequest.Deadline.Less(txn.Proto.Timestamp) {
return nil, roachpb.NewErrorWithTxn(roachpb.NewTransactionAbortedError(), &txn.Proto)
}
}
// This normally happens on the server and sent back in response
// headers, but this transaction was optimized away. The caller may
// still inspect the transaction struct, so we manually update it
// here to emulate a true transaction.
if endTxnRequest.Commit {
txn.Proto.Status = roachpb.COMMITTED
} else {
txn.Proto.Status = roachpb.ABORTED
}
txn.finalized = true
}
//.........这里部分代码省略.........
开发者ID:yangxuanjia,项目名称:cockroach,代码行数:101,代码来源:txn.go
示例16: TestReacquireLeaseOnRestart
// Verifies that an expired lease is released and a new lease is acquired on transaction
// restart.
//
// This test triggers the above scenario by making ReadWithinUncertaintyIntervalError advance
// the clock, so that the transaction timestamp exceeds the deadline of the EndTransactionRequest.
func TestReacquireLeaseOnRestart(t *testing.T) {
defer leaktest.AfterTest(t)()
var cmdFilters CommandFilters
cmdFilters.AppendFilter(checkEndTransactionTrigger, true)
var clockUpdate int32
testKey := []byte("test_key")
testingKnobs := &storage.StoreTestingKnobs{
TestingCommandFilter: cmdFilters.runFilters,
ClockBeforeSend: func(c *hlc.Clock, ba roachpb.BatchRequest) {
if atomic.LoadInt32(&clockUpdate) > 0 {
return
}
// Hack to advance the transaction timestamp on a transaction restart.
for _, union := range ba.Requests {
if req, ok := union.GetInner().(*roachpb.ScanRequest); ok {
if bytes.Contains(req.Key, testKey) {
atomic.AddInt32(&clockUpdate, 1)
now := c.Now()
now.WallTime += int64(5 * sql.LeaseDuration)
c.Update(now)
break
}
}
}
},
}
params, _ := createTestServerParams()
params.Knobs.Store = testingKnobs
s, sqlDB, _ := serverutils.StartServer(t, params)
defer s.Stopper().Stop()
var restartDone int32
cleanupFilter := cmdFilters.AppendFilter(
func(args storagebase.FilterArgs) *roachpb.Error {
if atomic.LoadInt32(&restartDone) > 0 {
return nil
}
if req, ok := args.Req.(*roachpb.ScanRequest); ok {
if bytes.Contains(req.Key, testKey) {
atomic.AddInt32(&restartDone, 1)
// Return ReadWithinUncertaintyIntervalError to update the transaction timestamp on retry.
txn := args.Hdr.Txn
txn.ResetObservedTimestamps()
now := s.Clock().Now()
txn.UpdateObservedTimestamp(
s.(*server.TestServer).Gossip().GetNodeID(), now)
return roachpb.NewErrorWithTxn(roachpb.NewReadWithinUncertaintyIntervalError(now, now), txn)
}
}
return nil
}, false)
defer cleanupFilter()
// Use a large max offset to avoid rejecting a transaction whose timestanp is in
// future (as we will advance the transaction timestamp with ReadWithinUncertaintyIntervalError).
s.Clock().SetMaxOffset(sql.LeaseDuration * 10)
sqlDB.SetMaxOpenConns(1)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (k TEXT PRIMARY KEY, v TEXT);
INSERT INTO t.test (k, v) VALUES ('test_key', 'test_val');
`); err != nil {
t.Fatal(err)
}
// Acquire the lease and enable the auto-retry. The first read attempt will trigger ReadWithinUncertaintyIntervalError
// and advance the transaction timestamp. The transaction timestamp will exceed the lease expiration
// time, and the second read attempt will re-acquire the lease.
if _, err := sqlDB.Exec(`
SELECT * from t.test WHERE k = 'test_key';
`); err != nil {
t.Fatal(err)
}
if u := atomic.LoadInt32(&clockUpdate); u != 1 {
t.Errorf("expected exacltly one clock update, but got %d", u)
}
if u := atomic.LoadInt32(&restartDone); u != 1 {
t.Errorf("expected exactly one restart, but got %d", u)
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:91,代码来源:txn_restart_test.go
示例17: updateState
// updateState updates the transaction state in both the success and
// error cases, applying those updates to the corresponding txnMeta
// object when adequate. It also updates certain errors with the
// updated transaction for use by client restarts.
func (tc *TxnCoordSender) updateState(ctx context.Context, ba roachpb.BatchRequest, br *roachpb.BatchResponse, pErr *roachpb.Error) *roachpb.Error {
sp, cleanupSp := tracing.SpanFromContext(opTxnCoordSender, tc.tracer, ctx)
defer cleanupSp()
newTxn := &roachpb.Transaction{}
newTxn.Update(ba.Txn)
if pErr == nil {
newTxn.Update(br.Txn)
} else {
newTxn.Update(pErr.GetTxn())
}
// If the request was successful but we're in a transaction which needs to
// restart but doesn't know it yet, let it restart now (as opposed to
// waiting until EndTransaction).
if pErr == nil && newTxn.Isolation == roachpb.SERIALIZABLE &&
!newTxn.OrigTimestamp.Equal(newTxn.Timestamp) {
pErr = roachpb.NewErrorWithTxn(roachpb.NewTransactionRetryError(), br.Txn)
br = nil
}
switch t := pErr.GetDetail().(type) {
case *roachpb.TransactionStatusError:
// Likely already committed or more obscure errors such as epoch or
// timestamp regressions; consider txn dead.
defer tc.cleanupTxn(sp, *pErr.GetTxn())
case *roachpb.OpRequiresTxnError:
panic("OpRequiresTxnError must not happen at this level")
case *roachpb.ReadWithinUncertaintyIntervalError:
// If the reader encountered a newer write within the uncertainty
// interval, we advance the txn's timestamp just past the last observed
// timestamp from the node.
restartTS, ok := newTxn.GetObservedTimestamp(pErr.OriginNode)
if !ok {
pErr = roachpb.NewError(util.Errorf("no observed timestamp for node %d found on uncertainty restart", pErr.OriginNode))
} else {
newTxn.Timestamp.Forward(restartTS)
newTxn.Restart(ba.UserPriority, newTxn.Priority, newTxn.Timestamp)
}
case *roachpb.TransactionAbortedError:
// Increase timestamp if applicable.
newTxn.Timestamp.Forward(pErr.GetTxn().Timestamp)
newTxn.Priority = pErr.GetTxn().Priority
// Clean up the freshly aborted transaction in defer(), avoiding a
// race with the state update below.
defer tc.cleanupTxn(sp, *newTxn)
case *roachpb.TransactionPushError:
// Increase timestamp if applicable, ensuring that we're
// just ahead of the pushee.
newTxn.Timestamp.Forward(t.PusheeTxn.Timestamp.Add(0, 1))
newTxn.Restart(ba.UserPriority, t.PusheeTxn.Priority-1, newTxn.Timestamp)
case *roachpb.TransactionRetryError:
newTxn.Restart(ba.UserPriority, pErr.GetTxn().Priority, newTxn.Timestamp)
case nil:
// Nothing to do here, avoid the default case.
default:
if pErr.GetTxn() != nil {
if pErr.CanRetry() {
panic("Retryable internal error must not happen at this level")
} else {
// Do not clean up the transaction here since the client might still
// want to continue the transaction. For example, a client might
// continue its transaction after receiving ConditionFailedError, which
// can come from a unique index violation.
}
}
}
if pErr != nil && pErr.GetTxn() != nil {
// Avoid changing existing errors because sometimes they escape into
// goroutines and then there are races. Fairly sure there isn't one
// here, but better safe than sorry.
pErrShallow := *pErr
pErrShallow.SetTxn(newTxn)
pErr = &pErrShallow
}
if newTxn.ID == nil {
return pErr
}
txnID := *newTxn.ID
tc.Lock()
defer tc.Unlock()
txnMeta := tc.txns[txnID]
// For successful transactional requests, keep the written intents and
// the updated transaction record to be sent along with the reply.
// The transaction metadata is created with the first writing operation.
// A tricky edge case is that of a transaction which "fails" on the
// first writing request, but actually manages to write some intents
// (for example, due to being multi-range). In this case, there will
// be an error, but the transaction will be marked as Writing and the
// coordinator must track the state, for the client's retry will be
// performed with a Writing transaction which the coordinator rejects
// unless it is tracking it (on top of it making sense to track it;
// after all, it **has** laid down intents and only the coordinator
// can augment a potential EndTransaction call). See #3303.
//.........这里部分代码省略.........
开发者ID:cuongdo,项目名称:cockroach,代码行数:101,代码来源:txn_coord_sender.go
示例18: TestCommitFinalizesTxnOnError
// Test that a COMMIT getting an error, retryable or not, leaves the txn
// finalized and not in Aborted/RestartWait (i.e. COMMIT, like ROLLBACK, is
// always final).
func TestCommitFinalizesTxnOnError(t *testing.T) {
defer leaktest.AfterTest(t)()
params, cmdFilters := createTestServerParams()
s, sqlDB, _ := serverutils.StartServer(t, params)
defer s.Stopper().Stop()
if _, err := sqlDB.Exec(`
CREATE DATABASE t; CREATE TABLE t.test (k INT PRIMARY KEY, v TEXT);
`); err != nil {
t.Fatal(err)
}
// We need to do everything on one connection as we'll want to observe the
// connection state after a COMMIT.
sqlDB.SetMaxOpenConns(1)
// Set up error injection that causes retries.
magicVals := createFilterVals(nil, nil)
magicVals.endTxnRestartCounts = map[string]int{
"boulanger": 1000, // restart many times, for all the tests below
}
defer cmdFilters.AppendFilter(
func(args storagebase.FilterArgs) *roachpb.Error {
if err := injectErrors(args.Req, args.Hdr, magicVals); err != nil {
return roachpb.NewErrorWithTxn(err, args.Hdr.Txn)
}
return nil
}, false)()
// We're going to test both errors that would leave the transaction in the
// RestartWait state and errors that would leave the transaction in Aborted,
// if they were to happen on any other statement than COMMIT.
// We do that by always injecting a retryable error at COMMIT, but once in a
// txn that had a "retry intent" (SAVEPOINT cockroach_restart), and once in a
// txn without it.
testCases := []struct {
retryIntent bool
}{
{false},
{true},
}
for _, tc := range testCases {
if _, err := sqlDB.Exec("BEGIN;"); err != nil {
t.Fatal(err)
}
if tc.retryIntent {
if _, err := sqlDB.Exec("SAVEPOINT cockroach_restart;"); err != nil {
t.Fatal(err)
}
}
if _, err := sqlDB.Exec("INSERT INTO t.test (k, v) VALUES (0, 'boulanger');"); err != nil {
t.Fatal(err)
}
if _, err := sqlDB.Exec("COMMIT;"); !testutils.IsError(err, "pq: restart transaction") {
t.Fatalf("unexpected error: %v", err)
}
// Check that we can start another txn on the (one and only) connection.
if _, err := sqlDB.Exec("BEGIN;END;"); err != nil {
t.Fatal(err)
}
}
}
开发者ID:yaojingguo,项目名称:cockroach,代码行数:66,代码来源:txn_restart_test.go
示例19: TestPropagateTxnOnError
// TestPropagateTxnOnError verifies that DistSender.sendChunk properly
// propagates the txn data to a next iteration. Use txn.Writing field to
// verify that.
func TestPropagateTxnOnError(t *testing.T) {
defer leaktest.AfterTest(t)()
// Set up a filter to so that the first CPut operation will
// get a ReadWithinUncertaintyIntervalError.
targetKey := roachpb.Key("b")
var numGets int32
ctx := server.NewTestContext()
ctx.TestingKnobs.StoreTestingKnobs.TestingCommandFilter =
func(fArgs storageutils.FilterArgs) *roachpb.Error {
_, ok := fArgs.Req.(*roachpb.ConditionalPutRequest)
if ok && fArgs.Req.Header().Key.Equal(targetKey) {
if atomic.AddInt32(&numGets, 1) == 1 {
z := roachpb.ZeroTimestamp
pErr := roachpb.NewReadWithinUncertaintyIntervalError(z, z)
return roachpb.NewErrorWithTxn(pErr, fArgs.Hdr.Txn)
}
}
return nil
}
s := server.StartTestServerWithContext(t, ctx)
defer s.Stop()
db := setupMultipleRanges(t, s, "b")
// Set the initial value on the target key "b".
origVal := "val"
if pErr := db.Put(targetKey, origVal); pErr != nil {
t.Fatal(pErr)
}
// The following txn creates a batch request that is split
// into two requests: Put and CPut. The CPut operation will
// get a ReadWithinUncertaintyIntervalError and the txn will be
// retried.
epoch := 0
if pErr := db.Txn(func(txn *client.Txn) *roachpb.Error {
epoch++
if epoch >= 2 {
// Writing must be true since we ran the BeginTransaction command.
if !txn.Proto.Writing {
t.Errorf("unexpected non-writing txn")
}
} else {
// Writing must be false since we haven't run any write command.
if txn.Proto.Writing {
t.Errorf("unexpected writing txn")
}
}
b := txn.NewBatch()
b.Put("a", "val")
b.CPut(targetKey, "new_val", origVal)
pErr := txn.CommitInBatch(b)
if epoch == 1 {
if _, ok := pErr.GetDetail().(*roachpb.ReadWithinUncertaintyIntervalError); ok {
if !pErr.GetTxn().Writing {
t.Errorf("unexpected non-writing txn on error")
}
} else {
t.Errorf("expected ReadWithinUncertaintyIntervalError, but got: %s", pErr)
}
}
return pErr
}); pErr != nil {
t.Errorf("unexpected error on transactional Puts: %s", pErr)
}
if epoch != 2 {
t.Errorf("unexpected epoch; the txn must be retried exactly once, but got %d", epoch)
}
}
开发者ID:petermattis,项目名称:cockroach,代码行数:75,代码来源:dist_sender_server_test.go
示例20: TestTxnUserRestart
// TestUserTxnRestart tests user-directed txn restarts.
// The test will inject and otherwise create retriable errors of various kinds
// and checks that we still manage to run a txn despite them.
func TestTxnUserRestart(t *testing.T) {
defer leaktest.AfterTest(t)()
params, cmdFilters := createTestServerParams()
params.Knobs.SQLExecutor = &sql.ExecutorTestingKnobs{FixTxnPriority: true}
s, sqlDB, _ := serverutils.StartServer(t, params)
defer s.Stopper().Stop()
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (k INT PRIMARY KEY, v TEXT);
`); err != nil {
t.Fatal(err)
}
// Set up error injection that causes retries.
testCases := []struct {
magicVals *filterVals
expectedErr string
}{
{
magicVals: createFilterVals(
map[string]int{"boulanger": 2}, // restartCounts
nil),
expectedErr: ".*encountered previous write with future timestamp.*",
},
{
magicVals: createFilterVals(
nil,
map[string]int{"boulanger": 2}), // abortCounts
expectedErr: ".*txn aborted.*",
},
}
for _, tc := range testCases {
for _, rs := range []rollbackStrategy{rollbackToSavepoint, declareSavepoint} {
cleanupFilter := cmdFilters.AppendFilter(
func(args storagebase.FilterArgs) *roachpb.Error {
if err := injectErrors(args.Req, args.Hdr, tc.magicVals); err != nil {
return roachpb.NewErrorWithTxn(err, args.Hdr.Txn)
}
return nil
}, false)
// Also inject an error at RELEASE time, besides the error injected by magicVals.
injectReleaseError := true
commitCount := s.MustGetSQLCounter(sql.MetaTxnCommit.Name)
// This is
|
请发表评论