// createTestRange creates a range using a blocking engine. Returns // the range clock's manual unix nanos time and the range. func createTestRangeWithClock(t *testing.T) (*Range, *hlc.ManualClock, *blockingEngine) { manual := hlc.ManualClock(0) clock := hlc.NewHLClock(manual.UnixNano) engine := newBlockingEngine() rng := NewRange(RangeMetadata{}, clock, engine, nil, nil) rng.Start() return rng, &manual, engine }
// createTestRange creates a new range initialized to the full extent // of the keyspace. The gossip instance is also returned for testing. func createTestRange(engine engine.Engine, t *testing.T) (*Range, *gossip.Gossip) { rm := RangeMetadata{ RangeID: 0, RangeDescriptor: testRangeDescriptor, } g := gossip.New() clock := hlc.NewHLClock(hlc.UnixNano) r := NewRange(rm, clock, engine, nil, g) r.Start() return r, g }
// createTestStore creates a test store using an in-memory // engine. Returns the store clock's manual unix nanos time and the // store. A single range from key "a" to key "z" is setup in the store // with a default replica descriptor (i.e. StoreID = 0, RangeID = 1, // etc.). The caller is responsible for closing the store on exit. func createTestStore(t *testing.T) (*Store, *hlc.ManualClock) { manual := hlc.ManualClock(0) clock := hlc.NewHLClock(manual.UnixNano) engine := NewInMem(Attributes{}, 1<<20) store := NewStore(clock, engine, nil) replica := Replica{RangeID: 1} _, err := store.CreateRange(Key("a"), Key("z"), []Replica{replica}) if err != nil { t.Fatal(err) } return store, &manual }
// TestReadTimestampCacheLayeredIntervals verifies the maximum // timestamp is chosen if previous reads have ranges which are // layered over each other. func TestReadTimestampCacheLayeredIntervals(t *testing.T) { manual := hlc.ManualClock(0) clock := hlc.NewHLClock(manual.UnixNano) clock.SetMaxDrift(maxClockSkew) rtc := NewReadTimestampCache(clock) manual = hlc.ManualClock(maxClockSkew.Nanoseconds() + 1) adTS := clock.Now() rtc.Add(engine.Key("a"), engine.Key("d"), adTS) beTS := clock.Now() rtc.Add(engine.Key("b"), engine.Key("e"), beTS) cTS := clock.Now() rtc.Add(engine.Key("c"), nil, cTS) // Try different sub ranges. if rtc.GetMax(engine.Key("a"), nil) != adTS { t.Error("expected \"a\" to have adTS timestamp") } if rtc.GetMax(engine.Key("b"), nil) != beTS { t.Error("expected \"b\" to have beTS timestamp") } if rtc.GetMax(engine.Key("c"), nil) != cTS { t.Error("expected \"b\" to have cTS timestamp") } if rtc.GetMax(engine.Key("d"), nil) != beTS { t.Error("expected \"d\" to have beTS timestamp") } if rtc.GetMax(engine.Key("a"), engine.Key("b")) != adTS { t.Error("expected \"a\"-\"b\" to have adTS timestamp") } if rtc.GetMax(engine.Key("a"), engine.Key("c")) != beTS { t.Error("expected \"a\"-\"c\" to have beTS timestamp") } if rtc.GetMax(engine.Key("a"), engine.Key("d")) != cTS { t.Error("expected \"a\"-\"d\" to have cTS timestamp") } if rtc.GetMax(engine.Key("b"), engine.Key("d")) != cTS { t.Error("expected \"b\"-\"d\" to have cTS timestamp") } if rtc.GetMax(engine.Key("c"), engine.Key("d")) != cTS { t.Error("expected \"c\"-\"d\" to have cTS timestamp") } if rtc.GetMax(engine.Key("c0"), engine.Key("d")) != beTS { t.Error("expected \"c0\"-\"d\" to have beTS timestamp") } }
// TestReadTimestampCacheEviction verifies the eviction of // read timestamp cache entries after minCacheWindow interval. func TestReadTimestampCacheEviction(t *testing.T) { manual := hlc.ManualClock(0) clock := hlc.NewHLClock(manual.UnixNano) clock.SetMaxDrift(maxClockSkew) rtc := NewReadTimestampCache(clock) // Increment time to the maxClockSkew high water mark + 1. manual = hlc.ManualClock(maxClockSkew.Nanoseconds() + 1) aTS := clock.Now() rtc.Add(engine.Key("a"), nil, aTS) // Increment time by the minCacheWindow and add another key. manual = hlc.ManualClock(int64(manual) + minCacheWindow.Nanoseconds()) rtc.Add(engine.Key("b"), nil, clock.Now()) // Verify looking up key "c" returns the new high water mark ("a"'s timestamp). if rtc.GetMax(engine.Key("c"), nil) != aTS { t.Error("expected high water mark %+v, got %+v", aTS, rtc.GetMax(engine.Key("c"), nil)) } }
// TestStoreInitAndBootstrap verifies store initialization and // bootstrap. func TestStoreInitAndBootstrap(t *testing.T) { manual := hlc.ManualClock(0) clock := hlc.NewHLClock(manual.UnixNano) engine := NewInMem(Attributes{}, 1<<20) store := NewStore(clock, engine, nil) defer store.Close() // Can't init as haven't bootstrapped. if err := store.Init(); err == nil { t.Error("expected failure init'ing un-bootstrapped store") } // Bootstrap with a fake ident. if err := store.Bootstrap(testIdent); err != nil { t.Errorf("error bootstrapping store: %v", err) } // Try to get 1st range--non-existent. if _, err := store.GetRange(1); err == nil { t.Error("expected error fetching non-existent range") } // Create range and fetch. if _, err := store.CreateRange(KeyMin, KeyMax, []Replica{}); err != nil { t.Errorf("failure to create first range: %v", err) } if _, err := store.GetRange(1); err != nil { t.Errorf("failure fetching 1st range: %v", err) } // Now, attempt to initialize a store with a now-bootstrapped engine. store = NewStore(clock, engine, nil) if err := store.Init(); err != nil { t.Errorf("failure initializing bootstrapped store: %v", err) } // 1st range should be available. if _, err := store.GetRange(1); err != nil { t.Errorf("failure fetching 1st range: %v", err) } }
func TestReadTimestampCacheClear(t *testing.T) { manual := hlc.ManualClock(0) clock := hlc.NewHLClock(manual.UnixNano) clock.SetMaxDrift(maxClockSkew) rtc := NewReadTimestampCache(clock) // Increment time to the maxClockSkew high water mark + 1. manual = hlc.ManualClock(maxClockSkew.Nanoseconds() + 1) ts := clock.Now() rtc.Add(engine.Key("a"), nil, ts) // Clear the cache, which will reset the high water mark to // the current time + maxClockSkew. rtc.Clear() // Fetching any keys should give current time + maxClockSkew expTS := clock.Timestamp() expTS.WallTime += maxClockSkew.Nanoseconds() if rtc.GetMax(engine.Key("a"), nil) != expTS { t.Error("expected \"a\" to have cleared timestamp") } }
// TestBootstrapOfNonEmptyStore verifies bootstrap failure if engine // is not empty. func TestBootstrapOfNonEmptyStore(t *testing.T) { engine := NewInMem(Attributes{}, 1<<20) // Put some random garbage into the engine. if err := engine.put(Key("foo"), []byte("bar")); err != nil { t.Errorf("failure putting key foo into engine: %v", err) } manual := hlc.ManualClock(0) clock := hlc.NewHLClock(manual.UnixNano) store := NewStore(clock, engine, nil) defer store.Close() // Can't init as haven't bootstrapped. if err := store.Init(); err == nil { t.Error("expected failure init'ing un-bootstrapped store") } // Bootstrap should fail on non-empty engine. if err := store.Bootstrap(testIdent); err == nil { t.Error("expected bootstrap error on non-empty store") } }
// createTestNode creates an rpc server using the specified address, // gossip instance, KV database and a node using the specified slice // of engines. The server and node are returned. If gossipBS is not // nil, the gossip bootstrap address is set to gossipBS. func createTestNode(addr net.Addr, engines []engine.Engine, gossipBS net.Addr, t *testing.T) ( *rpc.Server, *Node) { rpcServer := rpc.NewServer(addr) if err := rpcServer.Start(); err != nil { t.Fatal(err) } g := gossip.New() if gossipBS != nil { // Handle possibility of a :0 port specification. if gossipBS == addr { gossipBS = rpcServer.Addr() } g.SetBootstrap([]net.Addr{gossipBS}) g.Start(rpcServer) } db := kv.NewDB(g) node := NewNode(db, g) clock := hlc.NewHLClock(hlc.UnixNano) if err := node.start(rpcServer, clock, engines, nil); err != nil { t.Fatal(err) } return rpcServer, node }
// runStart starts the cockroach node using -stores as the list of // storage devices ("stores") on this machine and -gossip as the list // of "well-known" hosts used to join this node to the cockroach // cluster via the gossip network. func runStart(cmd *commander.Command, args []string) { glog.Info("Starting cockroach cluster") s, err := newServer() if err != nil { glog.Errorf("Failed to start Cockroach server: %v", err) return } // Create a new hybrid-logical clock using the internal clock. clock := hlc.NewHLClock(hlc.UnixNano) clock.SetMaxDrift(*maxDrift) // Init engines from -stores. engines, err := initEngines(*stores) if err != nil { glog.Errorf("Failed to initialize engines from -stores=%q: %v", *stores, err) return } if len(engines) == 0 { glog.Errorf("No valid engines specified after initializing from -stores=%q", *stores) return } err = s.start(clock, engines, false) defer s.stop() if err != nil { glog.Errorf("Cockroach server exited with error: %v", err) return } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill) // Block until one of the signals above is received. <-c }
func startServer() *server { serverTestOnce.Do(func() { s, err := newServer() if err != nil { glog.Fatal(err) } engines := []storage.Engine{storage.NewInMem(storage.Attributes{}, 1<<20)} if _, err := BootstrapCluster("cluster-1", engines[0]); err != nil { glog.Fatal(err) } clock := hlc.NewHLClock(hlc.UnixNano) err = s.start(clock, engines, true) // TODO(spencer): should shutdown server. if err != nil { glog.Fatalf("Could not start server: %s", err) } // Update the configuration variables to reflect the actual // sockets bound during this test. *httpAddr = (*s.httpListener).Addr().String() *rpcAddr = s.rpc.Addr().String() glog.Infof("Test server listening on http: %s, rpc: %s", *httpAddr, *rpcAddr) }) return s }
// BootstrapCluster bootstraps a store using the provided engine and // cluster ID. The bootstrapped store contains a single range spanning // all keys. Initial range lookup metadata is populated for the range. // // Returns a direct-access kv.LocalDB for unittest purposes only. func BootstrapCluster(clusterID string, eng engine.Engine) ( *kv.LocalDB, error) { sIdent := storage.StoreIdent{ ClusterID: clusterID, NodeID: 1, StoreID: 1, } clock := hlc.NewHLClock(hlc.UnixNano) now := clock.Now() s := storage.NewStore(clock, eng, nil) // Verify the store isn't already part of a cluster. if s.Ident.ClusterID != "" { return nil, util.Errorf("storage engine already belongs to a cluster (%s)", s.Ident.ClusterID) } // Bootstrap store to persist the store ident. if err := s.Bootstrap(sIdent); err != nil { return nil, err } if err := s.Init(); err != nil { return nil, err } // Create first range. replica := storage.Replica{ NodeID: 1, StoreID: 1, RangeID: 1, Attrs: engine.Attributes{}, } rng, err := s.CreateRange(engine.KeyMin, engine.KeyMax, []storage.Replica{replica}) if err != nil { return nil, err } if rng.Meta.RangeID != 1 { return nil, util.Errorf("expected range id of 1, got %d", rng.Meta.RangeID) } // Create a local DB to directly modify the new range. localDB := kv.NewLocalDB() localDB.AddStore(s) // Initialize range addressing records and default administrative configs. desc := storage.RangeDescriptor{ StartKey: engine.KeyMin, Replicas: []storage.Replica{replica}, } if err := kv.BootstrapRangeDescriptor(localDB, desc, now); err != nil { return nil, err } // Write default configs to local DB. if err := kv.BootstrapConfigs(localDB, now); err != nil { return nil, err } // Initialize node and store ids after the fact to account // for use of node ID = 1 and store ID = 1. if nodeID, err := allocateNodeID(localDB); nodeID != sIdent.NodeID || err != nil { return nil, util.Errorf("expected to intialize node id allocator to %d, got %d: %v", sIdent.NodeID, nodeID, err) } if storeID, err := allocateStoreIDs(sIdent.NodeID, 1, localDB); storeID != sIdent.StoreID || err != nil { return nil, util.Errorf("expected to intialize store id allocator to %d, got %d: %v", sIdent.StoreID, storeID, err) } return localDB, nil }
func TestReadTimestampCache(t *testing.T) { manual := hlc.ManualClock(0) clock := hlc.NewHLClock(manual.UnixNano) clock.SetMaxDrift(maxClockSkew) rtc := NewReadTimestampCache(clock) // First simulate a read of just "a" at time 0. rtc.Add(engine.Key("a"), nil, clock.Now()) // Verify GetMax returns the highWater mark which is maxClockSkew. if rtc.GetMax(engine.Key("a"), nil).WallTime != maxClockSkew.Nanoseconds() { t.Error("expected maxClockSkew for key \"a\"") } if rtc.GetMax(engine.Key("notincache"), nil).WallTime != maxClockSkew.Nanoseconds() { t.Error("expected maxClockSkew for key \"notincache\"") } // Advance the clock and verify same high water mark. manual = hlc.ManualClock(maxClockSkew.Nanoseconds() + 1) if rtc.GetMax(engine.Key("a"), nil).WallTime != maxClockSkew.Nanoseconds() { t.Error("expected maxClockSkew for key \"a\"") } if rtc.GetMax(engine.Key("notincache"), nil).WallTime != maxClockSkew.Nanoseconds() { t.Error("expected maxClockSkew for key \"notincache\"") } // Sim a read of "b"-"c" at time maxClockSkew + 1. ts := clock.Now() rtc.Add(engine.Key("b"), engine.Key("c"), ts) // Verify all permutations of direct and range access. if rtc.GetMax(engine.Key("b"), nil) != ts { t.Error("expected current time for key \"b\"; got %+v", rtc.GetMax(engine.Key("b"), nil)) } if rtc.GetMax(engine.Key("bb"), nil) != ts { t.Error("expected current time for key \"bb\"") } if rtc.GetMax(engine.Key("c"), nil).WallTime != maxClockSkew.Nanoseconds() { t.Error("expected maxClockSkew for key \"c\"") } if rtc.GetMax(engine.Key("b"), engine.Key("c")) != ts { t.Error("expected current time for key \"b\"-\"c\"") } if rtc.GetMax(engine.Key("bb"), engine.Key("bz")) != ts { t.Error("expected current time for key \"bb\"-\"bz\"") } if rtc.GetMax(engine.Key("a"), engine.Key("b")).WallTime != maxClockSkew.Nanoseconds() { t.Error("expected maxClockSkew for key \"a\"-\"b\"") } if rtc.GetMax(engine.Key("a"), engine.Key("bb")) != ts { t.Error("expected current time for key \"a\"-\"bb\"") } if rtc.GetMax(engine.Key("a"), engine.Key("d")) != ts { t.Error("expected current time for key \"a\"-\"d\"") } if rtc.GetMax(engine.Key("bz"), engine.Key("c")) != ts { t.Error("expected current time for key \"bz\"-\"c\"") } if rtc.GetMax(engine.Key("bz"), engine.Key("d")) != ts { t.Error("expected current time for key \"bz\"-\"d\"") } if rtc.GetMax(engine.Key("c"), engine.Key("d")).WallTime != maxClockSkew.Nanoseconds() { t.Error("expected maxClockSkew for key \"c\"-\"d\"") } }