[gold] Tools (and small fixes) from poking around time travel.

Change-Id: Ibfff2c69b409fa09c8be034bc5a516ed2fe10985
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/303340
Commit-Queue: Kevin Lubick <kjlubick@google.com>
Reviewed-by: Leandro Lovisolo <lovisolo@google.com>
diff --git a/golden/cmd/trace_tool/trace_tool.go b/golden/cmd/trace_tool/trace_tool.go
new file mode 100644
index 0000000..345e60a
--- /dev/null
+++ b/golden/cmd/trace_tool/trace_tool.go
@@ -0,0 +1,208 @@
+// The trace_tool executable is meant for directly interacting with the traces stored in
+// BigTable. It was last used to clean up bad data in a series of tiles.
+package main
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"sync/atomic"
+
+	"cloud.google.com/go/bigtable"
+	"go.skia.org/infra/go/bt"
+	"go.skia.org/infra/go/gitiles"
+	"go.skia.org/infra/go/gitstore/bt_gitstore"
+	"go.skia.org/infra/go/sklog"
+	"go.skia.org/infra/go/vcsinfo/bt_vcs"
+	"go.skia.org/infra/golden/go/tracestore/bt_tracestore"
+	"golang.org/x/sync/errgroup"
+)
+
+const (
+	instanceID = "production"  // The user is expected to edit these by hand or turn them into
+	projectID  = "skia-public" // flags
+
+	gitTableID   = "git-repos2"
+	traceBTTable = "gold-skia"
+	gitRepoURL   = "https://skia.googlesource.com/skia.git"
+)
+
+func main() {
+	flag.Parse()
+	ctx := context.Background()
+
+	btConf := &bt_gitstore.BTConfig{
+		InstanceID: instanceID,
+		ProjectID:  projectID,
+		TableID:    gitTableID,
+		AppProfile: bt.TestingAppProfile,
+	}
+
+	gitStore, err := bt_gitstore.New(ctx, btConf, gitRepoURL)
+	if err != nil {
+		sklog.Fatalf("Error instantiating gitstore: %s", err)
+	}
+
+	gitilesRepo := gitiles.NewRepo("", nil)
+	vcs, err := bt_vcs.New(ctx, gitStore, "master", gitilesRepo)
+	if err != nil {
+		sklog.Fatalf("Error creating BT-backed VCS instance: %s", err)
+	}
+
+	btc := bt_tracestore.BTConfig{
+		InstanceID: instanceID,
+		ProjectID:  projectID,
+		TableID:    traceBTTable,
+		VCS:        vcs,
+	}
+
+	offending, err := vcs.IndexOf(ctx, "a0f9a3e62afad0568380f982fe1a68f787682fa6")
+	if err != nil {
+		sklog.Fatalf("err", err)
+	}
+	sklog.Infof("offending commit index %d", offending)
+
+	n := vcs.LastNIndex(1)
+	sklog.Infof("Last commit was %s at %s index %d", n[0].Hash, n[0].Timestamp, n[0].Index)
+	tk, offset := bt_tracestore.GetTileKey(n[0].Index)
+	sklog.Infof("This is tile key %d offset %d", tk, offset)
+
+	tk++
+	sklog.Infof("Cleaning up the past to %d", tk)
+
+	client, err := bigtable.NewClient(ctx, btc.ProjectID, btc.InstanceID)
+	if err != nil {
+		sklog.Fatalf("Error creating client for project %s and instance %s: %s", btc.ProjectID, btc.InstanceID, err)
+	}
+
+	adminClient, err := bigtable.NewAdminClient(ctx, btc.ProjectID, btc.InstanceID)
+	if err != nil {
+		sklog.Fatalf("Error creating admin client for project %s and instance %s: %s", btc.ProjectID, btc.InstanceID, err)
+	}
+
+	must := func(err error) {
+		if err != nil {
+			sklog.Fatalf(err.Error())
+		}
+	}
+
+	must(countTraceRowsForTile(ctx, client, int(tk)))
+	must(deleteTraceDataForTile(ctx, adminClient, int(tk)))
+	must(countTraceRowsForTile(ctx, client, int(tk)))
+
+	must(countTraceOptionsForTile(ctx, client, int(tk)))
+	must(deleteTraceOptionsForTile(ctx, adminClient, int(tk)))
+	must(countTraceOptionsForTile(ctx, client, int(tk)))
+
+	must(deleteOPSForTile(ctx, adminClient, int(tk)))
+}
+
+func countTraceRowsForTile(ctx context.Context, bc *bigtable.Client, tk int) error {
+	count := int32(0)
+	table := bc.Open(traceBTTable)
+
+	eg, ctx := errgroup.WithContext(ctx)
+	for shard := 0; shard < bt_tracestore.DefaultShards; shard++ {
+		shardedPrefix := fmt.Sprintf("%02d:ts:t:%d", shard, tk)
+		eg.Go(func() error {
+			prefixRange := bigtable.PrefixRange(shardedPrefix)
+			return table.ReadRows(ctx, prefixRange, func(row bigtable.Row) bool {
+				atomic.AddInt32(&count, 1)
+				return true
+			}, bigtable.RowFilter(
+				bigtable.ChainFilters(
+					bigtable.StripValueFilter(), // https://cloud.google.com/bigtable/docs/using-filters#strip-value
+					bigtable.CellsPerRowLimitFilter(1),
+					bigtable.LatestNFilter(1),
+				),
+			))
+		})
+	}
+
+	err := eg.Wait()
+	sklog.Infof("Counted %d trace rows for tile %d", count, tk)
+	return err
+}
+
+func countTraceOptionsForTile(ctx context.Context, bc *bigtable.Client, tk int) error {
+	count := int32(0)
+	table := bc.Open(traceBTTable)
+
+	eg, ctx := errgroup.WithContext(ctx)
+	for shard := 0; shard < bt_tracestore.DefaultShards; shard++ {
+		shardedPrefix := fmt.Sprintf("%02d:ts:p:%d", shard, tk)
+		eg.Go(func() error {
+			prefixRange := bigtable.PrefixRange(shardedPrefix)
+			return table.ReadRows(ctx, prefixRange, func(row bigtable.Row) bool {
+				atomic.AddInt32(&count, 1)
+				return true
+			}, bigtable.RowFilter(
+				bigtable.ChainFilters(
+					bigtable.StripValueFilter(), // https://cloud.google.com/bigtable/docs/using-filters#strip-value
+					bigtable.CellsPerRowLimitFilter(1),
+					bigtable.LatestNFilter(1),
+				),
+			))
+		})
+	}
+
+	err := eg.Wait()
+	sklog.Infof("Counted %d trace options for tile %d", count, tk)
+	return err
+}
+
+func deleteTraceDataForTile(ctx context.Context, ac *bigtable.AdminClient, tk int) error {
+	for shard := 0; shard < bt_tracestore.DefaultShards; shard++ {
+		shardedPrefix := fmt.Sprintf("%02d:ts:t:%d", shard, tk)
+		sklog.Infof("Drop range %s", shardedPrefix)
+		err := ac.DropRowRange(ctx, traceBTTable, shardedPrefix)
+		if err != nil {
+			return err
+		}
+	}
+	sklog.Infof("finished dropping traces in tile %d", tk)
+	return nil
+}
+
+func deleteTraceOptionsForTile(ctx context.Context, ac *bigtable.AdminClient, tk int) error {
+	for shard := 0; shard < bt_tracestore.DefaultShards; shard++ {
+		shardedPrefix := fmt.Sprintf("%02d:ts:p:%d", shard, tk)
+		sklog.Infof("Drop range %s", shardedPrefix)
+		err := ac.DropRowRange(ctx, traceBTTable, shardedPrefix)
+		if err != nil {
+			return err
+		}
+	}
+	sklog.Infof("finished dropping options in tile %d", tk)
+	return nil
+}
+
+func deleteOPSForTile(ctx context.Context, ac *bigtable.AdminClient, tk int) error {
+	prefix := fmt.Sprintf(":ts:o:%d", tk)
+	sklog.Infof("Drop range %s", prefix)
+	err := ac.DropRowRange(ctx, traceBTTable, prefix)
+	if err != nil {
+		return err
+	}
+	sklog.Infof("finished dropping OPS in tile %d", tk)
+	return nil
+}
+
+func readTracesForTile(ctx context.Context, btc bt_tracestore.BTConfig, tk bt_tracestore.TileKey) {
+	traceStore, err := bt_tracestore.New(ctx, btc, false)
+	if err != nil {
+		sklog.Fatalf("Could not instantiate BT tracestore: %s", err)
+	}
+
+	sklog.Infof("Going to fetch tile %d", tk)
+
+	traceMap, _, err := traceStore.DEBUG_getTracesInRange(ctx, tk, tk, 0, 255)
+	if err != nil {
+		sklog.Fatalf("Could not get traces: %s", err)
+	}
+	for id, trace := range traceMap {
+		if trace.Keys["extra_config"] == "Direct3D" && trace.Keys["cpu_or_gpu_value"] == "RadeonHD7770" {
+			sklog.Infof("trace %s has digests %q", id, trace.Digests)
+		}
+	}
+}
diff --git a/golden/go/tracestore/bt_tracestore/bt_tracestore.go b/golden/go/tracestore/bt_tracestore/bt_tracestore.go
index 36f9117..f607afd 100644
--- a/golden/go/tracestore/bt_tracestore/bt_tracestore.go
+++ b/golden/go/tracestore/bt_tracestore/bt_tracestore.go
@@ -136,7 +136,7 @@
 
 	// Find out what tile we need to fetch and what index into that tile we need.
 	// Reminder that tileKeys start at 2^32-1 and decrease in value.
-	tileKey, commitIndex := b.getTileKey(repoIndex)
+	tileKey, commitIndex := GetTileKey(repoIndex)
 
 	// If these entries have any params we haven't seen before, we need to store those in BigTable.
 	ops, err := b.updateOrderedParamSet(ctx, tileKey, paramSet)
@@ -162,7 +162,7 @@
 // the rows that need updating and the mutations to apply to those rows.
 // Specifically, the mutations will add the given entries to BT, clearing out
 // anything that was there previously.
-func (b *BTTraceStore) createPutMutations(entries []*tracestore.Entry, tk tileKey, commitIndex int, ops *paramtools.OrderedParamSet, digestTS, optionsTS time.Time) ([]string, []*bigtable.Mutation, error) {
+func (b *BTTraceStore) createPutMutations(entries []*tracestore.Entry, tk TileKey, commitIndex int, ops *paramtools.OrderedParamSet, digestTS, optionsTS time.Time) ([]string, []*bigtable.Mutation, error) {
 	// These mutations...
 	mutations := make([]*bigtable.Mutation, 0, len(entries))
 	// .. should be applied to these rows.
@@ -222,10 +222,10 @@
 
 	// These commits could span across multiple tiles, so derive the tiles we need to query.
 	c := idxCommits[0]
-	startTileKey, startCommitIndex := b.getTileKey(c.Index)
+	startTileKey, startCommitIndex := GetTileKey(c.Index)
 
 	c = idxCommits[len(idxCommits)-1]
-	endTileKey, endCommitIndex := b.getTileKey(c.Index)
+	endTileKey, endCommitIndex := GetTileKey(c.Index)
 
 	var egroup errgroup.Group
 
@@ -268,9 +268,15 @@
 	return ret, commits, nil
 }
 
+// DEBUG_getTracesInRange exposes getTracesInRange to make it easy to call directly from a helper
+// executable such as trace_tool.
+func (b *BTTraceStore) DEBUG_getTracesInRange(ctx context.Context, startTileKey, endTileKey TileKey, startCommitIndex, endCommitIndex int) (traceMap, paramtools.ParamSet, error) {
+	return b.getTracesInRange(ctx, startTileKey, endTileKey, startCommitIndex, endCommitIndex)
+}
+
 // getTracesInRange returns a traceMap with data from the given start and stop points (tile and index).
 // It also includes the ParamSet for that range.
-func (b *BTTraceStore) getTracesInRange(ctx context.Context, startTileKey, endTileKey tileKey, startCommitIndex, endCommitIndex int) (traceMap, paramtools.ParamSet, error) {
+func (b *BTTraceStore) getTracesInRange(ctx context.Context, startTileKey, endTileKey TileKey, startCommitIndex, endCommitIndex int) (traceMap, paramtools.ParamSet, error) {
 	sklog.Debugf("getTracesInRange(%d, %d, %d, %d)", startTileKey, endTileKey, startCommitIndex, endCommitIndex)
 	// Query those tiles.
 	nTiles := int(startTileKey - endTileKey + 1)
@@ -280,7 +286,7 @@
 	var egroup errgroup.Group
 	tk := startTileKey
 	for idx := 0; idx < nTiles; idx++ {
-		func(idx int, tk tileKey) {
+		func(idx int, tk TileKey) {
 			egroup.Go(func() error {
 				var err error
 				encTiles[idx], err = b.loadTile(ctx, tk)
@@ -386,7 +392,7 @@
 	}
 
 	c := idxCommits[0]
-	endKey, endIdx := b.getTileKey(c.Index)
+	endKey, endIdx := GetTileKey(c.Index)
 	tileStartCommitIdx := c.Index - endIdx
 
 	// Given nCommits and the current index, we can figure out how many tiles to
@@ -512,17 +518,17 @@
 	return allCommits, denseCommits, nil
 }
 
-// getTileKey retrieves the tile key and the index of the commit in the given tile (commitIndex)
+// GetTileKey retrieves the tile key and the index of the commit in the given tile (commitIndex)
 // given the index of a commit in the repo (repoIndex).
 // commitIndex starts at 0 for the oldest commit in the tile.
-func (b *BTTraceStore) getTileKey(repoIndex int) (tileKey, int) {
+func GetTileKey(repoIndex int) (TileKey, int) {
 	tileIndex := int32(repoIndex) / DefaultTileSize
-	commitIndex := repoIndex % int(DefaultTileSize)
+	commitIndex := repoIndex % DefaultTileSize
 	return tileKeyFromIndex(tileIndex), commitIndex
 }
 
-// loadTile returns an *encTile corresponding to the tileKey.
-func (b *BTTraceStore) loadTile(ctx context.Context, tileKey tileKey) (*encTile, error) {
+// loadTile returns an *encTile corresponding to the TileKey.
+func (b *BTTraceStore) loadTile(ctx context.Context, tileKey TileKey) (*encTile, error) {
 	defer metrics2.FuncTimer().Stop()
 	var egroup errgroup.Group
 
@@ -558,7 +564,7 @@
 }
 
 // loadOptions returns the options map corresponding to the given tile.
-func (b *BTTraceStore) loadOptions(ctx context.Context, tileKey tileKey) (map[encodedTraceID]paramtools.Params, error) {
+func (b *BTTraceStore) loadOptions(ctx context.Context, tileKey TileKey) (map[encodedTraceID]paramtools.Params, error) {
 	defer metrics2.FuncTimer().Stop()
 
 	var egroup errgroup.Group
@@ -628,10 +634,10 @@
 	return ret, nil
 }
 
-// loadEncodedTraces returns all traces belonging to the given tileKey.
+// loadEncodedTraces returns all traces belonging to the given TileKey.
 // As outlined in BIGTABLE.md, the trace ids and the digest ids they
 // map to are in an encoded form and will need to be expanded prior to use.
-func (b *BTTraceStore) loadEncodedTraces(ctx context.Context, tileKey tileKey) ([]*encodedTracePair, error) {
+func (b *BTTraceStore) loadEncodedTraces(ctx context.Context, tileKey TileKey) ([]*encodedTracePair, error) {
 	defer metrics2.FuncTimer().Stop()
 	var egroup errgroup.Group
 	shardResults := [DefaultShards][]*encodedTracePair{}
@@ -696,7 +702,7 @@
 					bigtable.ChainFilters(
 						bigtable.FamilyFilter(traceFamily),
 						// can be used for local testing to keep RAM usage lower
-						//bigtable.RowSampleFilter(0.1),
+						// bigtable.RowSampleFilter(0.01),
 						bigtable.LatestNFilter(1),
 						bigtable.CellsPerRowLimitFilter(DefaultTileSize),
 					),
@@ -751,9 +757,9 @@
 }
 
 // calcShardedRowName deterministically assigns a shard for the given subkey (e.g. traceID)
-// Once this is done, the shard, rowtype, tileKey and the subkey are combined into a
+// Once this is done, the shard, rowtype, TileKey and the subkey are combined into a
 // single string to be used as a row name in BT.
-func (b *BTTraceStore) calcShardedRowName(tileKey tileKey, rowType, subkey string) string {
+func (b *BTTraceStore) calcShardedRowName(tileKey TileKey, rowType, subkey string) string {
 	shard := int32(crc32.ChecksumIEEE([]byte(subkey)) % uint32(DefaultShards))
 	return shardedRowName(shard, rowType, tileKey, subkey)
 }
@@ -761,8 +767,8 @@
 // Copied from btts.go in infra/perf
 
 // UpdateOrderedParamSet will add all params from 'p' to the OrderedParamSet
-// for 'tileKey' and write it back to BigTable.
-func (b *BTTraceStore) updateOrderedParamSet(ctx context.Context, tileKey tileKey, p paramtools.ParamSet) (*paramtools.OrderedParamSet, error) {
+// for 'TileKey' and write it back to BigTable.
+func (b *BTTraceStore) updateOrderedParamSet(ctx context.Context, tileKey TileKey, p paramtools.ParamSet) (*paramtools.OrderedParamSet, error) {
 	defer metrics2.FuncTimer().Stop()
 
 	tctx, cancel := context.WithTimeout(ctx, writeTimeout)
@@ -866,7 +872,7 @@
 // Note that it will create a new OpsCacheEntry if none exists.
 //
 // getOps returns false if the OPS in BT was empty, true otherwise (even if cached).
-func (b *BTTraceStore) getOPS(ctx context.Context, tk tileKey) (*opsCacheEntry, bool, error) {
+func (b *BTTraceStore) getOPS(ctx context.Context, tk TileKey) (*opsCacheEntry, bool, error) {
 	defer metrics2.FuncTimer().Stop()
 	if b.cacheOps {
 		entry, ok := b.opsCache.Load(tk.OpsRowName())
diff --git a/golden/go/tracestore/bt_tracestore/bt_tracestore_test.go b/golden/go/tracestore/bt_tracestore/bt_tracestore_test.go
index 3c0c313..7d1a083 100644
--- a/golden/go/tracestore/bt_tracestore/bt_tracestore_test.go
+++ b/golden/go/tracestore/bt_tracestore/bt_tracestore_test.go
@@ -637,51 +637,42 @@
 }
 
 // TestGetTileKey tests the internal workings of deriving a
-// tileKey from the commit index. See BIGTABLE.md for more.
+// TileKey from the commit index. See BIGTABLE.md for more.
 func TestGetTileKey(t *testing.T) {
-	unittest.LargeTest(t)
-	unittest.RequiresBigTableEmulator(t)
-
-	btConf := BTConfig{
-		// Leaving other things blank because we won't actually hit BT or use VCS.
-	}
-
-	ctx := context.Background()
-	traceStore, err := New(ctx, btConf, true)
-	require.NoError(t, err)
+	unittest.SmallTest(t)
 
 	type testStruct struct {
 		InputRepoIndex int
 
-		ExpectedKey   tileKey
+		ExpectedKey   TileKey
 		ExpectedIndex int
 	}
 	// test data is valid, but arbitrary.
 	tests := []testStruct{
 		{
 			InputRepoIndex: 0,
-			ExpectedKey:    tileKey(2147483647),
+			ExpectedKey:    TileKey(2147483647),
 			ExpectedIndex:  0,
 		},
 		{
 			InputRepoIndex: 10,
-			ExpectedKey:    tileKey(2147483647),
+			ExpectedKey:    TileKey(2147483647),
 			ExpectedIndex:  10,
 		},
 		{
 			InputRepoIndex: 300,
-			ExpectedKey:    tileKey(2147483646),
+			ExpectedKey:    TileKey(2147483646),
 			ExpectedIndex:  44,
 		},
 		{
 			InputRepoIndex: 123456,
-			ExpectedKey:    tileKey(2147483165),
+			ExpectedKey:    TileKey(2147483165),
 			ExpectedIndex:  64,
 		},
 	}
 
 	for _, test := range tests {
-		key, index := traceStore.getTileKey(test.InputRepoIndex)
+		key, index := GetTileKey(test.InputRepoIndex)
 		require.Equal(t, test.ExpectedKey, key)
 		require.Equal(t, test.ExpectedIndex, index)
 	}
@@ -703,7 +694,7 @@
 	require.NoError(t, err)
 
 	type testStruct struct {
-		InputKey     tileKey
+		InputKey     TileKey
 		InputRowType string
 		InputSubKey  string
 
@@ -712,14 +703,14 @@
 	// test data is valid, but arbitrary.
 	tests := []testStruct{
 		{
-			InputKey:     tileKey(2147483647),
+			InputKey:     TileKey(2147483647),
 			InputRowType: typeTrace,
 			InputSubKey:  ",0=1,1=3,3=0,",
 
 			ExpectedRowName: "09:ts:t:2147483647:,0=1,1=3,3=0,",
 		},
 		{
-			InputKey:     tileKey(2147483647),
+			InputKey:     TileKey(2147483647),
 			InputRowType: typeTrace,
 			InputSubKey:  ",0=1,1=3,9=0,",
 
diff --git a/golden/go/tracestore/bt_tracestore/types.go b/golden/go/tracestore/bt_tracestore/types.go
index 846095e..6bea097 100644
--- a/golden/go/tracestore/bt_tracestore/types.go
+++ b/golden/go/tracestore/bt_tracestore/types.go
@@ -73,7 +73,7 @@
 	maxTilesForDenseTile = 50
 
 	// BadTileKey is returned in error conditions.
-	badTileKey = tileKey(-1)
+	badTileKey = TileKey(-1)
 )
 
 var (
@@ -81,12 +81,12 @@
 	missingDigestBytes = []byte("")
 )
 
-// tileKey is the identifier for each tile held in BigTable.
+// TileKey is the identifier for each tile held in BigTable.
 //
 // Note that tile keys are in the opposite order of tile offset, that is, the first commit
 // in a repo goes in the first tile, which has key 2^32-1. We do this so more recent
 // tiles come first in sort order.
-type tileKey int32
+type TileKey int32
 
 // encodedTraceID is a shortened form of a tiling.TraceID, e.g. 0=1,1=3,3=0,
 // Those indices are references to the OrderedParamSet stored in encTile.
diff --git a/golden/go/tracestore/bt_tracestore/util.go b/golden/go/tracestore/bt_tracestore/util.go
index 3daa8ca..94f72e4 100644
--- a/golden/go/tracestore/bt_tracestore/util.go
+++ b/golden/go/tracestore/bt_tracestore/util.go
@@ -15,24 +15,24 @@
 	"go.skia.org/infra/golden/go/types"
 )
 
-// tileKeyFromIndex converts the tile index to the tileKey.
+// tileKeyFromIndex converts the tile index to the TileKey.
 // See BIGTABLE.md for more on this conversion.
-func tileKeyFromIndex(tileIndex int32) tileKey {
+func tileKeyFromIndex(tileIndex int32) TileKey {
 	if tileIndex < 0 {
 		return badTileKey
 	}
-	return tileKey(math.MaxInt32 - tileIndex)
+	return TileKey(math.MaxInt32 - tileIndex)
 }
 
 // OpsRowName returns the name of the BigTable row which stores the OrderedParamSet
 // for this tile.
-func (t tileKey) OpsRowName() string {
+func (t TileKey) OpsRowName() string {
 	return unshardedRowName(typeOPS, t)
 }
 
 // unshardedRowName calculates the row for the given data which all has the same format:
 // :[namespace]:[type]:[tile]:
-func unshardedRowName(rowType string, tileKey tileKey) string {
+func unshardedRowName(rowType string, tileKey TileKey) string {
 	return fmt.Sprintf(":%s:%s:%010d:", traceStoreNameSpace, rowType, tileKey)
 }
 
@@ -40,7 +40,7 @@
 // [shard]:[namespace]:[type]:[tile]:[subkey]
 // For some data types, where there is only one row,  or when doing a prefix-match,
 // subkey may be "".
-func shardedRowName(shard int32, rowType string, tileKey tileKey, subkey string) string {
+func shardedRowName(shard int32, rowType string, tileKey TileKey, subkey string) string {
 	return fmt.Sprintf("%02d:%s:%s:%010d:%s", shard, traceStoreNameSpace, rowType, tileKey, subkey)
 }
 
diff --git a/golden/go/tracestore/bt_tracestore/util_test.go b/golden/go/tracestore/bt_tracestore/util_test.go
index f332300..53426cc 100644
--- a/golden/go/tracestore/bt_tracestore/util_test.go
+++ b/golden/go/tracestore/bt_tracestore/util_test.go
@@ -17,9 +17,9 @@
 	unittest.SmallTest(t)
 
 	// spot-check some arbitrary values
-	require.Equal(t, tileKey(2147483647), tileKeyFromIndex(0))
-	require.Equal(t, tileKey(2147483451), tileKeyFromIndex(196))
-	require.Equal(t, tileKey(908536335), tileKeyFromIndex(1238947312))
+	require.Equal(t, TileKey(2147483647), tileKeyFromIndex(0))
+	require.Equal(t, TileKey(2147483451), tileKeyFromIndex(196))
+	require.Equal(t, TileKey(908536335), tileKeyFromIndex(1238947312))
 }
 
 func TestOpsRowName(t *testing.T) {
@@ -35,8 +35,8 @@
 	unittest.SmallTest(t)
 
 	shard := int32(3) // arbitrarily picked
-	tileZeroKey := tileKey(math.MaxInt32 - 1)
-	veryNewTileKey := tileKey(57)
+	tileZeroKey := TileKey(math.MaxInt32 - 1)
+	veryNewTileKey := TileKey(57)
 
 	// Example RowName for a trace
 	encodedTrace := ",0=1,1=3,3=0,"