package keepclient
import (
- "io/ioutil"
+ "io"
"sort"
+ "strconv"
+ "strings"
"sync"
"time"
)
// default size (currently 4) is used instead.
MaxBlocks int
- cache map[string]*cacheBlock
- mtx sync.Mutex
- setupOnce sync.Once
+ cache map[string]*cacheBlock
+ mtx sync.Mutex
}
const defaultMaxBlocks = 4
// there are no more than MaxBlocks left.
func (c *BlockCache) Sweep() {
max := c.MaxBlocks
- if max < defaultMaxBlocks {
+ if max == 0 {
max = defaultMaxBlocks
}
c.mtx.Lock()
}
}
+// ReadAt returns data from the cache, first retrieving it from Keep if
+// necessary.
+func (c *BlockCache) ReadAt(kc *KeepClient, locator string, p []byte, off int) (int, error) {
+ buf, err := c.Get(kc, locator)
+ if err != nil {
+ return 0, err
+ }
+ if off > len(buf) {
+ return 0, io.ErrUnexpectedEOF
+ }
+ return copy(p, buf[off:]), nil
+}
+
// Get returns data from the cache, first retrieving it from Keep if
// necessary.
func (c *BlockCache) Get(kc *KeepClient, locator string) ([]byte, error) {
- c.setupOnce.Do(c.setup)
cacheKey := locator[:32]
+ bufsize := BLOCKSIZE
+ if parts := strings.SplitN(locator, "+", 3); len(parts) >= 2 {
+ datasize, err := strconv.ParseInt(parts[1], 10, 32)
+ if err == nil && datasize >= 0 {
+ bufsize = int(datasize)
+ }
+ }
c.mtx.Lock()
+ if c.cache == nil {
+ c.cache = make(map[string]*cacheBlock)
+ }
b, ok := c.cache[cacheKey]
if !ok || b.err != nil {
b = &cacheBlock{
}
c.cache[cacheKey] = b
go func() {
- rdr, _, _, err := kc.Get(locator)
+ rdr, size, _, err := kc.Get(locator)
var data []byte
if err == nil {
- data, err = ioutil.ReadAll(rdr)
+ data = make([]byte, size, bufsize)
+ _, err = io.ReadFull(rdr, data)
err2 := rdr.Close()
if err == nil {
err = err2
return b.data, b.err
}
-func (c *BlockCache) setup() {
- c.cache = make(map[string]*cacheBlock)
+func (c *BlockCache) Clear() {
+ c.mtx.Lock()
+ c.cache = nil
+ c.mtx.Unlock()
}
type timeSlice []time.Time