// Indirectly this tests that the transaction remembers the NodeID of the node // being read from correctly, at least in this simple case. Not remembering the // node would lead to thousands of transaction restarts and almost certainly a // test timeout. func TestUncertaintyRestarts(t *testing.T) { { db, eng, clock, mClock, _, transport, err := createTestDB() if err != nil { t.Fatal(err) } defer transport.Close() // Set a large offset so that a busy restart-loop // really shows. Also makes sure that the values // we write in the future below don't actually // wind up in the past. offset := 4000 * time.Millisecond clock.SetMaxOffset(offset) key := proto.Key("key") value := proto.Value{ Bytes: nil, // Set for each Put } // With the correct restart behaviour, we see only one restart // and the value read is the very first one (as nothing else // has been written) wantedBytes := []byte("value-0") txnOpts := &client.TransactionOptions{ Name: "uncertainty", } gr := &proto.GetResponse{} i := -1 tErr := db.RunTransaction(txnOpts, func(txn *client.KV) error { i++ mClock.Increment(1) futureTS := clock.Now() futureTS.WallTime++ value.Bytes = []byte(fmt.Sprintf("value-%d", i)) err = engine.MVCCPut(eng, nil, key, futureTS, value, nil) if err != nil { t.Fatal(err) } gr.Reset() if err := txn.Call(proto.Get, proto.GetArgs(key), gr); err != nil { return err } if gr.Value == nil || !bytes.Equal(gr.Value.Bytes, wantedBytes) { t.Fatalf("%d: read wrong value: %v, wanted %q", i, gr.Value, wantedBytes) } return nil }) if i != 1 { t.Errorf("txn restarted %d times, expected only one restart", i) } if tErr != nil { t.Fatal(tErr) } } }
// Indirectly this tests that the transaction remembers the NodeID of the node // being read from correctly, at least in this simple case. Not remembering the // node would lead to thousands of transaction restarts and almost certainly a // test timeout. func TestUncertaintyRestarts(t *testing.T) { defer leaktest.AfterTest(t) s := createTestDB(t) defer s.Stop() // Set a large offset so that a busy restart-loop // really shows. Also makes sure that the values // we write in the future below don't actually // wind up in the past. offset := 4000 * time.Millisecond s.Clock.SetMaxOffset(offset) key := proto.Key("key") value := proto.Value{ Bytes: nil, // Set for each Put } // With the correct restart behaviour, we see only one restart // and the value read is the very first one (as nothing else // has been written) wantedBytes := []byte("value-0") i := -1 tErr := s.DB.Txn(func(txn *client.Txn) error { i++ s.Manual.Increment(1) futureTS := s.Clock.Now() futureTS.WallTime++ value.Bytes = []byte(fmt.Sprintf("value-%d", i)) if err := engine.MVCCPut(s.Eng, nil, key, futureTS, value, nil); err != nil { t.Fatal(err) } gr, err := txn.Get(key) if err != nil { return err } if !gr.Exists() || !bytes.Equal(gr.ValueBytes(), wantedBytes) { t.Fatalf("%d: read wrong value: %v, wanted %q", i, gr.Value, wantedBytes) } return nil }) if i != 1 { t.Errorf("txn restarted %d times, expected only one restart", i) } if tErr != nil { t.Fatal(tErr) } }
// marshalValue returns a proto.Value initialized from the source // reflect.Value, returning an error if the types are not compatible. func marshalValue(v reflect.Value) (proto.Value, error) { var r proto.Value if !v.IsValid() { return r, nil } switch t := v.Interface().(type) { case nil: return r, nil case string: r.Bytes = []byte(t) return r, nil case []byte: r.Bytes = t return r, nil case proto.Key: r.Bytes = []byte(t) return r, nil case gogoproto.Message: var err error r.Bytes, err = gogoproto.Marshal(t) return r, err case encoding.BinaryMarshaler: var err error r.Bytes, err = t.MarshalBinary() return r, err } switch v.Kind() { case reflect.Bool: i := int64(0) if v.Bool() { i = 1 } r.SetInteger(i) return r, nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: r.SetInteger(v.Int()) return r, nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: r.SetInteger(int64(v.Uint())) return r, nil case reflect.Float32, reflect.Float64: r.SetInteger(int64(math.Float64bits(v.Float()))) return r, nil case reflect.String: r.Bytes = []byte(v.String()) return r, nil } return r, fmt.Errorf("unable to marshal value: %s", v) }