15 // The default compression level of new CacheDir objects.
16 const DefaultCompressionLevel = gzip.BestCompression
18 func (cd *CacheDir) SetCompressionLevel(level int) {
20 defer cd.mutex.Unlock()
22 cd.compressionLevel = level
25 // Retrieves the current gzip compression level.
26 func (cd *CacheDir) GetCompressionLevel() int {
28 defer cd.mutex.Unlock()
30 return cd.compressionLevel
33 // Calls Get to retrieve the requested key from the cache.
35 // If the key is expired, then it is removed from the cache.
36 func (cd *CacheDir) GetAndExpire(v interface{}, max time.Duration, key ...CacheKey) (mtime time.Time, expired bool, err error) {
37 mtime, err = cd.Get(v, key...)
39 if err != nil && time.Now().Sub(mtime) > max {
41 err = cd.Delete(key...)
46 // Gets the requested key from the cache. The given interface{} must be a pointer
47 // or otherwise be modifiable; otherwise Get will panic.
48 func (cd *CacheDir) Get(v interface{}, key ...CacheKey) (mtime time.Time, err error) {
49 val := reflect.ValueOf(v)
50 if k := val.Kind(); k == reflect.Ptr || k == reflect.Interface {
55 panic("(*CacheDir).Get(): given interface{} is not setable")
58 lock, err := cd.Lock(key...)
63 // We may unlock it early
69 fh, err := cd.Open(key...)
73 stat, err := fh.Stat()
77 mtime = stat.ModTime()
80 if _, err = io.Copy(&buf, fh); err != nil {
84 if err = fh.Close(); err != nil {
94 gz, err := gzip.NewReader(&buf)
99 if e := gz.Close(); err == nil {
104 switch f := gz.Header.Comment; f {
106 dec := gob.NewDecoder(gz)
109 err = errors.New(fmt.Sprintf("Cached data (format %q) is not in a known format", f))
115 // Stores the given interface{} in the cache. Returns the size of the resulting file and the error, if any.
117 // Compresses the resulting data using gzip with the compression level set by SetCompressionLevel().
118 func (cd *CacheDir) Set(v interface{}, key ...CacheKey) (n int64, err error) {
119 if v := reflect.ValueOf(v); !v.IsValid() {
120 panic("reflect.ValueOf() returned invaled value")
121 } else if k := v.Kind(); k == reflect.Ptr || k == reflect.Interface {
123 return // no point in saving nil
127 // First we encode to memory -- we don't want to create/truncate a file and put bad data in it.
128 buf := bytes.Buffer{}
129 gz, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
133 gz.Header.Comment = "encoding/gob"
135 enc := gob.NewEncoder(gz)
138 if e := gz.Close(); err == nil {
146 // We have good data, time to actually put it in the cache
147 lock, err := cd.Lock(key...)
152 case os.IsNotExist(err):
158 fh, err := cd.Create(key...)
163 // the file didn't exist before, but it does now
164 lock, err = cd.Lock(key...)
172 if e := fh.Close(); err == nil {
176 n, err = io.Copy(fh, &buf)