blob: 4bfe6ba7270b1c8cd310ec9e9e35002fcef084aa [file] [log] [blame]
// Copyright 2015 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package dscache
import (
"bytes"
"crypto/sha1"
"encoding/base64"
"fmt"
"time"
"github.com/luci/gae/service/datastore"
"github.com/luci/gae/service/datastore/serialize"
)
var (
// InstanceEnabledStatic allows you to statically (e.g. in an init() function)
// bypass this filter by setting it to false. This takes effect when the
// application calls IsGloballyEnabled.
InstanceEnabledStatic = true
// LockTimeSeconds is the number of seconds that a "lock" memcache entry will
// have its expiration set to. It's set to just over half of the frontend
// request handler timeout (currently 60 seconds).
LockTimeSeconds = 31
// CacheTimeSeconds is the default number of seconds that a cached entity will
// be retained (memcache contention notwithstanding). A value of 0 is
// infinite. This is #seconds instead of time.Duration, because memcache
// truncates expiration to the second, which means a sub-second amount would
// actually truncate to an infinite timeout.
CacheTimeSeconds = int64((time.Hour * 24).Seconds())
// CompressionThreshold is the number of bytes of entity value after which
// compression kicks in.
CompressionThreshold = 860
// DefaultShards is the default number of key sharding to do.
DefaultShards = 1
// DefaultEnabled indicates whether or not caching is globally enabled or
// disabled by default. Can still be overridden by CacheEnableMeta.
DefaultEnabled = true
)
const (
// MemcacheVersion will be incremented in the event that the in-memcache
// representation of the cache data is modified.
MemcacheVersion = "1"
// KeyFormat is the format string used to generate memcache keys. It's
// gae:<version>:<shard#>:<base64_std_nopad(sha1(datastore.Key))>
KeyFormat = "gae:" + MemcacheVersion + ":%x:%s"
// Sha1B64Padding is the number of padding characters a base64 encoding of
// a sha1 has.
Sha1B64Padding = 1
// MaxShards is the maximum number of shards a single entity can have.
MaxShards = 256
// MaxShardsLen is the number of characters in the key the shard field
// occupies.
MaxShardsLen = len("ff")
// InternalGAEPadding is the estimated internal padding size that GAE takes
// per memcache line.
// https://cloud.google.com/appengine/docs/go/memcache/#Go_Limits
InternalGAEPadding = 96
// ValueSizeLimit is the maximum encoded size a datastore key+entry may
// occupy. If a datastore entity is too large, it will have an indefinite
// lock which will cause all clients to fetch it from the datastore.
ValueSizeLimit = (1000 * 1000) - InternalGAEPadding - MaxShardsLen
// CacheEnableMeta is the gae metadata key name for whether or not dscache
// is enabled for an entity type at all.
CacheEnableMeta = "dscache.enable"
// CacheExpirationMeta is the gae metadata key name for the default
// expiration time (in seconds) for an entity type.
CacheExpirationMeta = "dscache.expiration"
// NonceBytes is the number of bytes to use in the 'lock' nonce.
NonceBytes = 8
// GlobalEnabledCheckInterval is how frequently IsGloballyEnabled should check
// the globalEnabled datastore entry.
GlobalEnabledCheckInterval = 5 * time.Minute
)
// internalValueSizeLimit is a var for testing purposes.
var internalValueSizeLimit = ValueSizeLimit
// CompressionType is the type of compression a single memcache entry has.
type CompressionType byte
// Types of compression. ZlibCompression uses "compress/zlib".
const (
NoCompression CompressionType = iota
ZlibCompression
)
func (c CompressionType) String() string {
switch c {
case NoCompression:
return "NoCompression"
case ZlibCompression:
return "ZlibCompression"
default:
return fmt.Sprintf("UNKNOWN_CompressionType(%d)", c)
}
}
// FlagValue is used to indicate if a memcache entry currently contains an
// item or a lock.
type FlagValue uint32
// States for a memcache entry. ItemUNKNOWN exists to distinguish the default
// zero state from a valid state, but shouldn't ever be observed in memcache. .
const (
ItemUKNONWN FlagValue = iota
ItemHasData
ItemHasLock
)
// MakeMemcacheKey generates a memcache key for the given datastore Key. This
// is useful for debugging.
func MakeMemcacheKey(shard int, k *datastore.Key) string {
return fmt.Sprintf(KeyFormat, shard, HashKey(k))
}
// HashKey generates just the hashed portion of the MemcacheKey.
func HashKey(k *datastore.Key) string {
dgst := sha1.Sum(serialize.ToBytes(k))
buf := bytes.Buffer{}
enc := base64.NewEncoder(base64.StdEncoding, &buf)
_, _ = enc.Write(dgst[:])
enc.Close()
return buf.String()[:buf.Len()-Sha1B64Padding]
}