Example #1
0
func TestPrettyPrint(t *testing.T) {
	defer leaktest.AfterTest(t)

	tm, _ := time.Parse(time.UnixDate, "Sat Mar  7 11:06:39 UTC 2015")

	testCases := []struct {
		key roachpb.Key
		exp string
	}{
		// local
		{StoreIdentKey(), "/Local/Store/storeIdent"},
		{StoreGossipKey(), "/Local/Store/gossipBootstrap"},
		{SequenceCacheKeyPrefix(roachpb.RangeID(1000001), []byte("test0")), `/Local/RangeID/1000001/SequenceCache/"test0"`},
		{SequenceCacheKey(roachpb.RangeID(1000001), []byte("test0"), uint32(111), uint32(222)), `/Local/RangeID/1000001/SequenceCache/"test0"/epoch:111/seq:222`},
		{RaftLeaderLeaseKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftLeaderLease"},
		{RaftTombstoneKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftTombstone"},
		{RaftHardStateKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftHardState"},
		{RaftAppliedIndexKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftAppliedIndex"},
		{RaftLogKey(roachpb.RangeID(1000001), uint64(200001)), "/Local/RangeID/1000001/RaftLog/logIndex:200001"},
		{RaftTruncatedStateKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftTruncatedState"},
		{RaftLastIndexKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftLastIndex"},
		{RangeLastVerificationTimestampKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RangeLastVerificationTimestamp"},
		{RangeStatsKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RangeStats"},

		{MakeRangeKeyPrefix(roachpb.RKey("ok")), `/Local/Range/"ok"`},
		{RangeDescriptorKey(roachpb.RKey("111")), `/Local/Range/RangeDescriptor/"111"`},
		{RangeTreeNodeKey(roachpb.RKey("111")), `/Local/Range/RangeTreeNode/"111"`},
		{TransactionKey(roachpb.Key("111"), []byte("22222")), `/Local/Range/Transaction/addrKey:/"111"/id:"22222"`},

		{LocalMax, "/Local/Max"},

		// system
		{roachpb.MakeKey(Meta2Prefix, roachpb.Key("foo")), `/Meta2/"foo"`},
		{roachpb.MakeKey(Meta1Prefix, roachpb.Key("foo")), `/Meta1/"foo"`},

		{StoreStatusKey(2222), "/System/StatusStore/2222"},
		{NodeStatusKey(1111), "/System/StatusNode/1111"},

		{SystemMax, "/System/Max"},

		// table
		{UserTableDataMin, "/Table/50"},
		{MakeTablePrefix(111), "/Table/111"},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey("foo")), `/Table/42/"foo"`},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeFloat(nil, float64(233.221112)))), "/Table/42/233.221112"},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeVarint(nil, 1222)), roachpb.RKey(encoding.EncodeString(nil, "handsome man"))), `/Table/42/1222/"handsome man"`},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeBytes(nil, []byte{1, 2, 8, 255}))), `/Table/42/"\x01\x02\b\xff"`},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeBytes(nil, []byte{1, 2, 8, 255})), roachpb.RKey("bar")), `/Table/42/"\x01\x02\b\xff"/"bar"`},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeNull(nil))), "/Table/42/NULL"},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeNotNull(nil))), "/Table/42/#"},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeTime(nil, tm))), "/Table/42/Sat Mar  7 11:06:39 UTC 2015"},

		// others
		{MakeKey([]byte("")), "/Min"},
		{MakeKey(MakeTablePrefix(42), roachpb.RKey([]byte{0x20, 'a', 0x00, 0x02})), "/Table/42/<util/encoding/encoding.go:407: unknown escape>"},
	}
	for i, test := range testCases {
		keyInfo := PrettyPrint(test.key)
		if test.exp != keyInfo {
			t.Fatalf("%d: expected %s, got %s", i, test.exp, keyInfo)
		}

		if test.exp != test.key.String() {
			t.Fatalf("%d: expected %s, got %s", i, test.exp, keyInfo)
		}
	}
}
Example #2
0
// makeSpans constructs the spans for an index given a set of constraints.
func makeSpans(constraints indexConstraints, tableID ID, indexID IndexID) []span {
	prefix := roachpb.Key(MakeIndexKeyPrefix(tableID, indexID))
	spans := []span{{
		start: append(roachpb.Key(nil), prefix...),
		end:   append(roachpb.Key(nil), prefix...),
	}}
	var buf [100]byte

	for i, c := range constraints {
		// Is this the last end constraint? We perform special processing on the
		// last end constraint to account for the exclusive nature of the scan end
		// key.
		lastEnd := c.end != nil &&
			(i+1 == len(constraints) || constraints[i+1].end == nil)

		if (c.start != nil && c.start.Operator == parser.In) ||
			(c.end != nil && c.end.Operator == parser.In) {
			var e *parser.ComparisonExpr
			if c.start != nil && c.start.Operator == parser.In {
				e = c.start
			} else {
				e = c.end
			}

			// Special handling of IN exprssions. Such expressions apply to both the
			// start and end key, but also cause an explosion in the number of spans
			// searched within an index.
			tuple, ok := e.Right.(parser.DTuple)
			if !ok {
				break
			}

			// For each of the existing spans and for each value in the tuple, create
			// a new span.
			existingSpans := spans
			spans = make([]span, 0, len(existingSpans)*len(tuple))
			for _, datum := range tuple {
				var start, end []byte

				switch t := datum.(type) {
				case parser.DTuple:
					start = buf[:0]
					for _, i := range c.tupleMap {
						var err error
						if start, err = encodeTableKey(start, t[i]); err != nil {
							panic(err)
						}
					}

					end = start
					if lastEnd {
						end = nil
						for i := range c.tupleMap {
							d := t[c.tupleMap[i]]
							if i+1 == len(c.tupleMap) {
								d = d.Next()
							}
							var err error
							if end, err = encodeTableKey(end, d); err != nil {
								panic(err)
							}
						}
					}

				default:
					var err error
					if start, err = encodeTableKey(buf[:0], datum); err != nil {
						panic(err)
					}

					end = start
					if lastEnd {
						var err error
						if end, err = encodeTableKey(nil, datum.Next()); err != nil {
							panic(err)
						}
					}
				}

				for _, s := range existingSpans {
					if c.start != nil {
						s.start = append(append(roachpb.Key(nil), s.start...), start...)
					}
					if c.end != nil {
						s.end = append(append(roachpb.Key(nil), s.end...), end...)
					}
					spans = append(spans, s)
				}
			}

			continue
		}

		if c.start != nil {
			// We have a start constraint.
			switch c.start.Operator {
			case parser.NE, parser.IsNot:
				// A != or IS NOT NULL expression allows us to constrain the start of
				// the range to not include NULL.
				for i := range spans {
					spans[i].start = encoding.EncodeNotNull(spans[i].start)
				}
			default:
				if datum, ok := c.start.Right.(parser.Datum); ok {
					key, err := encodeTableKey(buf[:0], datum)
					if err != nil {
						panic(err)
					}
					// Append the constraint to all of the existing spans.
					for i := range spans {
						spans[i].start = append(spans[i].start, key...)
					}
				}
			}
		}

		if c.end != nil {
			// We have an end constraint.
			switch c.end.Operator {
			case parser.Is:
				// An IS NULL expressions allows us to constrain the end of the range
				// to stop at NULL.
				for i := range spans {
					spans[i].end = encoding.EncodeNotNull(spans[i].end)
				}
			default:
				if datum, ok := c.end.Right.(parser.Datum); ok {
					if lastEnd && c.end.Operator != parser.LT {
						datum = datum.Next()
					}
					key, err := encodeTableKey(buf[:0], datum)
					if err != nil {
						panic(err)
					}
					// Append the constraint to all of the existing spans.
					for i := range spans {
						spans[i].end = append(spans[i].end, key...)
					}
				}

				if c.start == nil && (i == 0 || constraints[i-1].start != nil) {
					// This is the first constraint for which we don't have a start
					// constraint. Add a not-NULL endpoint.
					for i := range spans {
						spans[i].start = encoding.EncodeNotNull(spans[i].start)
					}
				}
			}
		}
	}

	if len(constraints) == 0 || constraints[0].end == nil {
		for i := range spans {
			spans[i].end = spans[i].end.PrefixEnd()
		}
	}

	// Remove any spans which are empty. This can happen for constraints such as
	// "a > 1 AND a < 2" which we do not simplify to false but which is treated
	// as "a >= 2 AND a < 2" for span generation.
	n := 0
	for _, s := range spans {
		if bytes.Compare(s.start, s.end) < 0 {
			spans[n] = s
			n++
		}
	}
	spans = spans[:n]

	return spans
}