// write writes the values to the entry in the partition, creating the entry // if it does not exist. // write is safe for use by multiple goroutines. func (p *partition) write(key string, values Values) error { p.mu.RLock() e, ok := p.store[key] p.mu.RUnlock() if ok { // Hot path. return e.add(values) } p.mu.Lock() defer p.mu.Unlock() // Check again. if e, ok = p.store[key]; ok { return e.add(values) } // Create a new entry using a preallocated size if we have a hint available. hint, _ := p.entrySizeHints[xxhash.Sum64([]byte(key))] e, err := newEntryValues(values, hint) if err != nil { return err } p.store[key] = e return nil }
// reset resets the partition by reinitialising the store. reset returns hints // about sizes that the entries within the store could be reallocated with. func (p *partition) reset() { p.mu.Lock() defer p.mu.Unlock() // Collect the allocated sizes of values for each entry in the store. p.entrySizeHints = make(map[uint64]int) for k, entry := range p.store { // If the capacity is large then there are many values in the entry. // Store a hint to pre-allocate the next time we see the same entry. if cap(entry.values) > 128 { // 4 x the default entry capacity size. p.entrySizeHints[xxhash.Sum64([]byte(k))] = cap(entry.values) } } // Reset the store. p.store = make(map[string]*entry, len(p.store)) }
// getPartition retrieves the hash ring partition associated with the provided // key. func (r *ring) getPartition(key string) *partition { return r.continuum[int(uint8(xxhash.Sum64([]byte(key))))] }