// loadLastIndex retrieves the last index from storage. func (r *Replica) loadLastIndex() (uint64, error) { lastIndex := uint64(0) v, _, err := engine.MVCCGet(r.rm.Engine(), keys.RaftLastIndexKey(r.Desc().RangeID), roachpb.ZeroTimestamp, true /* consistent */, nil) if err != nil { return 0, err } if v != nil { var err error _, lastIndex, err = encoding.DecodeUint64(v.GetRawBytes()) if err != nil { return 0, err } } else { // The log is empty, which means we are either starting from scratch // or the entire log has been truncated away. raftTruncatedState // handles both cases. lastEnt, err := r.raftTruncatedState() if err != nil { return 0, err } lastIndex = lastEnt.Index } return lastIndex, nil }
func (rc *ResponseCache) decodeResponseCacheKey(encKey proto.EncodedKey) (proto.ClientCmdID, error) { ret := proto.ClientCmdID{} key, _, isValue := engine.MVCCDecodeKey(encKey) if isValue { return ret, util.Errorf("key %s is not a raw MVCC value", encKey) } if !bytes.HasPrefix(key, keys.LocalRangeIDPrefix) { return ret, util.Errorf("key %s does not have %s prefix", key, keys.LocalRangeIDPrefix) } // Cut the prefix and the Raft ID. b := key[len(keys.LocalRangeIDPrefix):] b, _ = encoding.DecodeUvarint(b) if !bytes.HasPrefix(b, keys.LocalResponseCacheSuffix) { return ret, util.Errorf("key %s does not contain the response cache suffix %s", key, keys.LocalResponseCacheSuffix) } // Cut the response cache suffix. b = b[len(keys.LocalResponseCacheSuffix):] // Now, decode the command ID. b, wt := encoding.DecodeUvarint(b) b, rd := encoding.DecodeUint64(b) if len(b) > 0 { return ret, util.Errorf("key %s has leftover bytes after decode: %s; indicates corrupt key", encKey, b) } ret.WallTime = int64(wt) ret.Random = int64(rd) return ret, nil }
// GetInteger decodes an int64 value from the bytes field of the receiver. If // the bytes field is not 0 or 8 bytes in length an error will be returned. func (v *Value) GetInteger() (int64, error) { if v == nil || len(v.Bytes) == 0 { return 0, nil } if len(v.Bytes) != 8 { return 0, fmt.Errorf("uint64 value should be exactly 8 bytes: %d", len(v.Bytes)) } _, u := encoding.DecodeUint64(v.Bytes) return int64(u), nil }
func raftLogKeyPrint(key roachpb.Key) string { var logIndex uint64 var err error key, logIndex, err = encoding.DecodeUint64(key) if err != nil { return fmt.Sprintf("/err<%v:%q>", err, []byte(key)) } return fmt.Sprintf("/logIndex:%d", logIndex) }
// GetInt decodes an int64 value from the bytes field of the receiver. If the // bytes field is not 8 bytes in length or the tag is not INT an error will be // returned. func (v *Value) GetInt() (int64, error) { if tag := v.GetTag(); tag != ValueType_INT { return 0, fmt.Errorf("value type is not INT: %s", tag) } if len(v.Bytes) != 8 { return 0, fmt.Errorf("uint64 value should be exactly 8 bytes: %d", len(v.Bytes)) } _, u := encoding.DecodeUint64(v.Bytes) return int64(u), nil }
// GetFloat decodes a float64 value from the bytes field of the receiver. If // the bytes field is not 8 bytes in length or the tag is not FLOAT an error // will be returned. func (v *Value) GetFloat() (float64, error) { if tag := v.GetTag(); tag != ValueType_FLOAT { return 0, fmt.Errorf("value type is not FLOAT: %s", tag) } if len(v.Bytes) != 8 { return 0, fmt.Errorf("float64 value should be exactly 8 bytes: %d", len(v.Bytes)) } _, u := encoding.DecodeUint64(v.Bytes) return math.Float64frombits(u), nil }
// GetInt decodes an int64 value from the bytes field of the receiver. If the // bytes field is not 8 bytes in length or the tag is not INT an error will be // returned. func (v Value) GetInt() (int64, error) { if tag := v.Tag; tag != ValueType_INT { return 0, fmt.Errorf("value type is not %s: %s", ValueType_INT, tag) } if len(v.RawBytes) != 8 { return 0, fmt.Errorf("uint64 value should be exactly 8 bytes: %d", len(v.RawBytes)) } _, u, err := encoding.DecodeUint64(v.RawBytes) if err != nil { return 0, err } return int64(u), nil }
// GetFloat decodes a float64 value from the bytes field of the receiver. If // the bytes field is not 8 bytes in length or the tag is not FLOAT an error // will be returned. func (v Value) GetFloat() (float64, error) { if tag := v.Tag; tag != ValueType_FLOAT { return 0, fmt.Errorf("value type is not %s: %s", ValueType_FLOAT, tag) } if len(v.RawBytes) != 8 { return 0, fmt.Errorf("float64 value should be exactly 8 bytes: %d", len(v.RawBytes)) } _, u, err := encoding.DecodeUint64(v.RawBytes) if err != nil { return 0, err } return math.Float64frombits(u), nil }
// ValueInt returns the value decoded as an int64. This method will panic if // the value cannot be decoded as an int64. func (kv *KeyValue) ValueInt() int64 { if kv.Value == nil { return 0 } if i, ok := kv.Value.(*int64); ok { return *i } b := kv.ValueBytes() if len(b) == 0 { return 0 } _, uint64val := roachencoding.DecodeUint64(b) return int64(uint64val) }
// loadAppliedIndex retrieves the applied index from the supplied engine. func (r *Range) loadAppliedIndex(eng engine.Engine) (uint64, error) { var appliedIndex uint64 if r.isInitialized() { appliedIndex = raftInitialLogIndex } else { appliedIndex = 0 } v, _, err := engine.MVCCGet(eng, keys.RaftAppliedIndexKey(r.Desc().RaftID), proto.ZeroTimestamp, true, nil) if err != nil { return 0, err } if v != nil { _, appliedIndex = encoding.DecodeUint64(v.Bytes) } return appliedIndex, nil }
// loadAppliedIndex retrieves the applied index from the supplied engine. func (r *Replica) loadAppliedIndex(eng engine.Engine) (uint64, error) { var appliedIndex uint64 if r.isInitialized() { appliedIndex = raftInitialLogIndex } else { appliedIndex = 0 } v, _, err := engine.MVCCGet(eng, keys.RaftAppliedIndexKey(r.Desc().RangeID), roachpb.ZeroTimestamp, true, nil) if err != nil { return 0, err } if v != nil { var err error _, appliedIndex, err = encoding.DecodeUint64(v.GetRawBytes()) if err != nil { return 0, err } } return appliedIndex, nil }
// outputDotFile generates a .dot file describing the current state of // the gossip network. nodes is a map from network address to gossip // node. edgeSet is empty on the first invocation, but // its content is set to encompass the entire set of edges in the // network when this method returns. It should be resupplied with each // successive invocation, as it is used to determine which edges are // new and which have been deleted and show those changes visually in // the output graph. New edges are drawn green; edges which were // removed over the course of the last simulation step(s) are drawn in // a lightly-dashed red. // // The format of the output looks like this: // // digraph G { // node [shape=record]; // node1 [fontsize=12,label="{Node 1|MH=3}"] // node1 -> node3 [color=green] // node1 -> node4 // node1 -> node5 [color=red,style=dotted] // node2 [fontsize=24,label="{Node 2|MH=2}"] // node2 -> node5 // node3 [fontsize=18,label="{Node 3|MH=5}"] // node3 -> node5 // node3 -> node4 // node4 [fontsize=24,label="{Node 4|MH=4}"] // node4 -> node2 // node5 [fontsize=24,label="{Node 5|MH=1}"] // node5 -> node2 // node5 -> node3 // } // // Returns the name of the output file and a boolean for whether or not // the network has quiesced (that is, no new edges, and all nodes are // connected). func outputDotFile(dotFN string, cycle int, network *simulation.Network, edgeSet map[string]edge) (string, bool) { f, err := os.Create(dotFN) if err != nil { log.Fatalf("unable to create temp file: %s", err) } defer f.Close() // Determine maximum number of incoming connections. Create outgoing // edges, keeping track of which are new since last time (added=true). outgoingMap := make(edgeMap) var maxIncoming int quiescent := true // The order the graph file is written influences the arrangement // of nodes in the output image, so it makes sense to eliminate // randomness here. Unfortunately with graphviz it's fairly hard // to get a consistent ordering. for _, simNode := range network.Nodes { node := simNode.Gossip incoming := node.Incoming() for _, iNode := range incoming { e := edge{dest: node.GetNodeID()} key := fmt.Sprintf("%d:%d", iNode, node.GetNodeID()) if _, ok := edgeSet[key]; !ok { e.added = true quiescent = false } delete(edgeSet, key) outgoingMap.addEdge(iNode, e) } if len(incoming) > maxIncoming { maxIncoming = len(incoming) } } // Find all edges which were deleted. for key, e := range edgeSet { e.added = false e.deleted = true quiescent = false nodeID, err := strconv.Atoi(strings.Split(key, ":")[0]) if err != nil { log.Fatal(err) } outgoingMap.addEdge(roachpb.NodeID(nodeID), e) delete(edgeSet, key) } f.WriteString("digraph G {\n") f.WriteString("node [shape=record];\n") for _, simNode := range network.Nodes { node := simNode.Gossip var missing []roachpb.NodeID var totalAge int64 for _, otherNode := range network.Nodes { if otherNode == simNode { continue // skip the node's own info } infoKey := otherNode.Addr.String() // GetInfo returns an error if the info is missing. if info, err := node.GetInfo(infoKey); err != nil { missing = append(missing, otherNode.Gossip.GetNodeID()) quiescent = false } else { _, val, err := encoding.DecodeUint64(info) if err != nil { log.Fatalf("bad decode of node info cycle: %s", err) } totalAge += int64(cycle) - int64(val) } } log.Infof("node %d: missing infos for nodes %s", node.GetNodeID(), missing) var sentinelAge int64 // GetInfo returns an error if the info is missing. if info, err := node.GetInfo(gossip.KeySentinel); err != nil { log.Infof("error getting info for sentinel gossip key %q: %s", gossip.KeySentinel, err) } else { _, val, err := encoding.DecodeUint64(info) if err != nil { log.Fatalf("bad decode of sentinel cycle: %s", err) } sentinelAge = int64(cycle) - int64(val) } var age, nodeColor string if len(missing) > 0 { nodeColor = "color=red," age = fmt.Sprintf("missing %d", len(missing)) } else { age = strconv.FormatFloat(float64(totalAge)/float64(len(network.Nodes)-1-len(missing)), 'f', 4, 64) } fontSize := minDotFontSize if maxIncoming > 0 { fontSize = minDotFontSize + int(math.Floor(float64(len(node.Incoming())* (maxDotFontSize-minDotFontSize))/float64(maxIncoming))) } f.WriteString(fmt.Sprintf("\t%s [%sfontsize=%d,label=\"{%s|AA=%s, MH=%d, SA=%d}\"]\n", node.GetNodeID(), nodeColor, fontSize, node.GetNodeID(), age, node.MaxHops(), sentinelAge)) outgoing := outgoingMap[node.GetNodeID()] for _, e := range outgoing { destSimNode, ok := network.GetNodeFromID(e.dest) if !ok { continue } dest := destSimNode.Gossip style := "" if e.added { style = " [color=green]" } else if e.deleted { style = " [color=red,style=dotted]" } f.WriteString(fmt.Sprintf("\t%s -> %s%s\n", node.GetNodeID(), dest.GetNodeID(), style)) if !e.deleted { edgeSet[fmt.Sprintf("%d:%d", node.GetNodeID(), e.dest)] = e } } } f.WriteString("}\n") return f.Name(), quiescent }