func (s *BoltStore) removeFromRootLabel(tx *bolt.Tx, itemType string, itemID uint64, userid []byte) {
	index := tx.Bucket(boltBucketLabelRootIndex)
	id := index.Get(userid)
	if id != nil {
		label := itemType + "/" + strconv.FormatUint(itemID, 10)
		b := tx.Bucket(boltBucketLabels)
		v := b.Get(id)
		root := &Label{}
		root.UnmarshalMsg(v)

		if strings.Contains(root.Content, ","+label) {
			root.Content = strings.Replace(root.Content, ","+label, "", 1)
		} else if strings.HasPrefix(root.Content, label+",") {
			root.Content = strings.Replace(root.Content, label+",", "", 1)
		} else {
			root.Content = strings.Replace(root.Content, label, "", 1)
		}

		v, err := root.MarshalMsg(nil)
		if err != nil {
			return
		}

		b.Put(id, v)
	}
}
// Inserts a key into the database.
func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) {
	var err error
	keys, value := randKeys(), randValue()

	// Retrieve root bucket.
	b := tx.Bucket(keys[0])
	if b == nil {
		b, err = tx.CreateBucket(keys[0])
		if err != nil {
			panic("create bucket: " + err.Error())
		}
	}

	// Create nested buckets, if necessary.
	for _, key := range keys[1 : len(keys)-1] {
		child := b.Bucket(key)
		if child != nil {
			b = child
		} else {
			b, err = b.CreateBucket(key)
			if err != nil {
				panic("create bucket: " + err.Error())
			}
		}
	}

	// Insert into database.
	if err := b.Put(keys[len(keys)-1], value); err != nil {
		panic("put: " + err.Error())
	}

	// Insert into in-memory database.
	qdb.Put(keys, value)
}
// Retrieves a key from the database and verifies that it is what is expected.
func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) {
	// Randomly retrieve an existing exist.
	keys := qdb.Rand()
	if len(keys) == 0 {
		return
	}

	// Retrieve root bucket.
	b := tx.Bucket(keys[0])
	if b == nil {
		panic(fmt.Sprintf("bucket[0] expected: %08x\n", trunc(keys[0], 4)))
	}

	// Drill into nested buckets.
	for _, key := range keys[1 : len(keys)-1] {
		b = b.Bucket(key)
		if b == nil {
			panic(fmt.Sprintf("bucket[n] expected: %v -> %v\n", keys, key))
		}
	}

	// Verify key/value on the final bucket.
	expected := qdb.Get(keys)
	actual := b.Get(keys[len(keys)-1])
	if !bytes.Equal(actual, expected) {
		fmt.Println("=== EXPECTED ===")
		fmt.Println(expected)
		fmt.Println("=== ACTUAL ===")
		fmt.Println(actual)
		fmt.Println("=== END ===")
		panic("value mismatch")
	}
}
func (s *BoltStore) getLabel(tx *bolt.Tx, id []byte) *Label {
	b := tx.Bucket(boltBucketLabels)
	v := b.Get(id)
	if v != nil {
		label := &Label{}
		label.UnmarshalMsg(v)
		return label
	}
	return nil
}
func (s *BoltStore) addEvent(tx *bolt.Tx, event *Event, userid uint64) error {
	b := tx.Bucket(boltBucketEvents)
	eventID, err := b.NextSequence()
	if err != nil {
		return err
	}

	v, err := event.MarshalMsg(nil)
	if err != nil {
		return err
	}

	id := make([]byte, 24)
	binary.BigEndian.PutUint64(id[:8], userid)
	binary.BigEndian.PutUint64(id[8:16], event.ClientTS)
	binary.BigEndian.PutUint64(id[16:], eventID)

	return b.Put(id, v)
}
func (s *BoltStore) saveEpisode(tx *bolt.Tx, ep *Episode) error {
	index := tx.Bucket(boltBucketEpisodeGUIDIndex)
	guid := []byte(ep.GUID)
	if index.Get(guid) != nil {
		return nil
	}

	var err error
	b := tx.Bucket(boltBucketEpisodes)
	ep.ID, err = b.NextSequence()
	if err != nil {
		return err
	}

	ep.EncodeFeed()
	v, err := ep.MarshalMsg(nil)
	if err != nil {
		return err
	}

	id := uint64Bytes(ep.ID)
	err = index.Put(guid, id)
	if err != nil {
		return err
	}

	idxID := make([]byte, 16)
	binary.BigEndian.PutUint64(idxID[:8], ep.CastID)
	binary.BigEndian.PutUint64(idxID[8:], ep.ID)
	castIndex := tx.Bucket(boltBucketEpisodeCastIDIndex)
	err = castIndex.Put(idxID, id)
	if err != nil {
		return err
	}

	crawlTSIndex := tx.Bucket(boltBucketEpisodeCrawlTSIndex)
	idxID = make([]byte, 24)
	binary.BigEndian.PutUint64(idxID[:8], uint64(ep.CrawlTS))
	binary.BigEndian.PutUint64(idxID[8:16], ep.ID)
	binary.BigEndian.PutUint64(idxID[16:], ep.CastID)
	err = crawlTSIndex.Put(idxID, id)
	if err != nil {
		return err
	}

	return b.Put(id, v)
}
func (s *BoltStore) addToRootLabel(tx *bolt.Tx, itemType string, itemID uint64, userid []byte) {
	var err error
	label := itemType + "/" + strconv.FormatUint(itemID, 10)
	b := tx.Bucket(boltBucketLabels)
	index := tx.Bucket(boltBucketLabelRootIndex)
	id := index.Get(userid)
	if id != nil {
		v := b.Get(id)
		root := &Label{}
		root.UnmarshalMsg(v)
		if strings.Contains(root.Content, label) {
			return
		}

		if root.Content != "" {
			root.Content += ","
		}
		root.Content += label

		v, err = root.MarshalMsg(nil)
		if err != nil {
			return
		}

		b.Put(id, v)
	} else {
		root := &Label{
			Name:    "root",
			Content: itemType + "/" + strconv.FormatUint(itemID, 10),
			Root:    true,
		}

		root.ID, err = b.NextSequence()
		if err != nil {
			return
		}

		v, err := root.MarshalMsg(nil)
		if err != nil {
			return
		}

		id = uint64Bytes(root.ID)
		index.Put(userid, id)

		idxID := []byte{}
		idxID = append(idxID, userid...)
		idxID = append(idxID, id...)
		index = tx.Bucket(boltBucketLabelUserIDIndex)
		err = index.Put(idxID, id)
		if err != nil {
			return
		}

		b.Put(id, v)
	}
}