blob: 346305abcf1123f5c4af12c8338d15ff503cac4d [file] [log] [blame]
// Copyright 2016 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package shards provides a low level support for implementing sharded set of
// []byte blobs.
package shards
import (
"bytes"
"encoding/gob"
"hash/fnv"
"sort"
)
// Shard is a set of byte blobs.
//
// It represents s single shard of a sharded set.
type Shard map[string]struct{}
// ParseShard deserializes a shard (serialized with Serialize).
func ParseShard(blob []byte) (Shard, error) {
var sorted []string
dec := gob.NewDecoder(bytes.NewReader(blob))
if err := dec.Decode(&sorted); err != nil {
return nil, err
}
shard := make(Shard, len(sorted))
for _, blob := range sorted {
shard[blob] = struct{}{}
}
return shard, nil
}
// Serialize serializes the shard to a byte buffer.
func (s Shard) Serialize() []byte {
sorted := make([]string, 0, len(s))
for blob := range s {
sorted = append(sorted, blob)
}
sort.Strings(sorted)
out := bytes.Buffer{}
enc := gob.NewEncoder(&out)
err := enc.Encode(sorted)
if err != nil {
panic("impossible error when encoding []string")
}
return out.Bytes()
}
// Set is an array of shards (representing a single sharded set).
//
// The size of the array is number of shards in the set. Allocate it using
// regular make(...).
type Set []Shard
// Insert adds a blob into the sharded set.
func (s Set) Insert(blob []byte) {
shard := &s[ShardIndex(blob, len(s))]
if *shard == nil {
*shard = make(Shard)
}
(*shard)[string(blob)] = struct{}{}
}
// ShardIndex returns an index of a shard to use when storing given blob.
func ShardIndex(member []byte, shardCount int) int {
hash := fnv.New32()
hash.Write(member)
return int(hash.Sum32() % uint32(shardCount))
}