-
Notifications
You must be signed in to change notification settings - Fork 596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discuss about MultiGet #334
Comments
Is it correct to proceed sequentially without using a goroutine? |
Yes, depend how you do locking. I think we should start with simple solution that we can iterate on with benchmark. |
Thank you so much for the advice. |
func (c *BigCache) MultiGet(keys ...string) ([][]byte, error) {
entries := make([][]byte, len(keys))
var firstErr error
for i, key := range keys {
hashedKey := c.hash.Sum64(key)
shard := c.getShard(hashedKey)
entry, err := shard.get(key, hashedKey)
if firstErr == nil {
firstErr = err
}
entries[i] = entry
}
return entries, firstErr
} This is the benchmark test code. func BenchmarkMultiReadFromCache(b *testing.B) {
for _, shards := range []int{1, 512, 1024, 8192} {
for _, readCount := range []int{1, 4, 8, 16} {
b.Run(fmt.Sprintf("%d-shards,%d-count", shards, readCount), func(b *testing.B) {
multiReadFromCache(b, shards, true, readCount)
})
}
}
}
func BenchmarkSequentialReadFromCache(b *testing.B) {
for _, shards := range []int{1, 512, 1024, 8192} {
for _, readCount := range []int{1, 4, 8, 16} {
b.Run(fmt.Sprintf("%d-shards,%d-count", shards, readCount), func(b *testing.B) {
multiReadFromCache(b, shards, false, readCount)
})
}
}
}
func multiReadFromCache(b *testing.B, shards int, isMulti bool, readCount int) {
cache, _ := NewBigCache(Config{
Shards: shards,
LifeWindow: 1000 * time.Second,
MaxEntriesInWindow: max(b.N, 100),
MaxEntrySize: 500,
})
for i := 0; i < b.N; i++ {
cache.Set(strconv.Itoa(i), message)
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
b.ReportAllocs()
for pb.Next() {
keys := []string{}
for i := 0; i < readCount; i++ {
keys = append(keys, strconv.Itoa(rand.Intn(b.N)))
}
if isMulti {
cache.MultiGet(keys...)
} else {
for _, key := range keys {
cache.Get(key)
}
}
}
})
}
MultiGet is not performing very well. os: windows |
Doing a multiget on the shard gives similar results. type entryData struct {
hashedKey uint64
entryKey string
index int
}
func (s *cacheShard) multiGet(entryDatas []entryData, entries [][]byte) {
s.lock.RLock()
defer s.lock.RUnlock()
for _, entryData := range entryDatas {
wrappedEntry, err := s.getWrappedEntry(entryData.hashedKey)
if err != nil {
continue
}
if entryKey := readKeyFromEntry(wrappedEntry); entryData.entryKey != entryKey {
s.collision()
if s.isVerbose {
s.logger.Printf("Collision detected. Both %q and %q have the same hash %x", entryData.entryKey, entryKey, entryData.hashedKey)
}
continue
}
entry := readEntry(wrappedEntry)
s.hit(entryData.hashedKey)
entries[entryData.index] = entry
}
} |
Why there are negative numbers in the table? |
negative numbers means MultirRead is faster than SequentialRead (MultirRead - SequentialRead). |
What is the issue you are having?
I saw #324 and I'm in the process of implementing MultiGet.
I don't know how to handle [cacheshard.hits] .
Test
Environment:
The text was updated successfully, but these errors were encountered: