// TestCoordinatorHeartbeat verifies periodic heartbeat of the // transaction record. func TestCoordinatorHeartbeat(t *testing.T) { db, _, manual := createTestDB(t) defer db.Close() // Set heartbeat interval to 1ms for testing. db.coordinator.heartbeatInterval = 1 * time.Millisecond txnID := engine.Key("txn") <-db.Put(createPutRequest(engine.Key("a"), []byte("value"), txnID)) // Verify 3 heartbeats. var heartbeatTS proto.Timestamp for i := 0; i < 3; i++ { if err := util.IsTrueWithin(func() bool { txn := proto.Transaction{} if ok, _, err := storage.GetProto(db, engine.MakeKey(engine.KeyLocalTransactionPrefix, txnID), &txn); !ok || err != nil { return false } // Advance clock by 1ns. *manual = hlc.ManualClock(*manual + 1) if heartbeatTS.Less(txn.LastHeartbeat) { heartbeatTS = txn.LastHeartbeat return true } return false }, 50*time.Millisecond); err != nil { t.Error("expected initial heartbeat within 50ms") } } }
// Get retrieves the zone configuration for the specified key. If the // key is empty, all zone configurations are returned. Otherwise, the // leading "/" path delimiter is stripped and the zone configuration // matching the remainder is retrieved. Note that this will retrieve // the default zone config if "key" is equal to "/", and will list all // configs if "key" is equal to "". The body result contains // JSON-formatted output for a listing of keys and YAML-formatted // output for retrieval of a zone config. func (zh *zoneHandler) Get(path string, r *http.Request) (body []byte, contentType string, err error) { // Scan all zones if the key is empty. if len(path) == 0 { sr := <-zh.db.Scan(&proto.ScanRequest{ RequestHeader: proto.RequestHeader{ Key: engine.KeyConfigZonePrefix, EndKey: engine.PrefixEndKey(engine.KeyConfigZonePrefix), User: storage.UserRoot, }, MaxResults: maxGetResults, }) if sr.Error != nil { err = sr.GoError() return } if len(sr.Rows) == maxGetResults { log.Warningf("retrieved maximum number of results (%d); some may be missing", maxGetResults) } var prefixes []string for _, kv := range sr.Rows { trimmed := bytes.TrimPrefix(kv.Key, engine.KeyConfigZonePrefix) prefixes = append(prefixes, url.QueryEscape(string(trimmed))) } // JSON-encode the prefixes array. contentType = "application/json" if body, err = json.Marshal(prefixes); err != nil { err = util.Errorf("unable to format zone configurations: %v", err) } } else { zoneKey := engine.MakeKey(engine.KeyConfigZonePrefix, engine.Key(path[1:])) var ok bool config := &proto.ZoneConfig{} if ok, _, err = storage.GetProto(zh.db, zoneKey, config); err != nil { return } // On get, if there's no zone config for the requested prefix, // return a not found error. if !ok { err = util.Errorf("no config found for key prefix %q", path) return } var out []byte if out, err = yaml.Marshal(config); err != nil { err = util.Errorf("unable to marshal zone config %+v to yaml: %v", config, err) return } if !utf8.ValidString(string(out)) { err = util.Errorf("config contents not valid utf8: %q", out) return } contentType = "text/yaml" body = out } return }