blob: 10782009ac189de2f67267975978edd71dba776f [file] [log] [blame]
package lib
import (
"sync"
"time"
"v.io/core/veyron2/context"
"v.io/core/veyron2/ipc"
"v.io/core/veyron2/ipc/reserved"
"v.io/core/veyron2/vdl/vdlroot/src/signature"
"v.io/core/veyron2/verror2"
)
type SignatureManager interface {
Signature(ctx *context.T, name string, client ipc.Client, opts ...ipc.CallOpt) ([]signature.Interface, error)
FlushCacheEntry(name string)
}
// signatureManager can be used to discover the signature of a remote service
// It has built-in caching and TTL support.
type signatureManager struct {
// protects the cache and initialization
sync.Mutex
// map of name to service signature and last-accessed time
// TODO(aghassemi) GC for expired cache entries
cache map[string]*cacheEntry
}
// NewSignatureManager creates and initialized a new Signature Manager
func NewSignatureManager() SignatureManager {
return &signatureManager{cache: make(map[string]*cacheEntry)}
}
const (
// ttl from the last-accessed time.
ttl = time.Duration(time.Hour)
)
type cacheEntry struct {
sig []signature.Interface
lastAccessed time.Time
}
// expired returns whether the cache entry is expired or not
func (c cacheEntry) expired() bool {
return time.Now().Sub(c.lastAccessed) > ttl
}
const pkgPath = "v.io/wspr/veyron/services/wsprd/lib"
// Signature uses the given client to fetch the signature for the given service
// name. It either returns the signature from the cache, or blocks until it
// fetches the signature from the remote server.
func (sm *signatureManager) Signature(ctx *context.T, name string, client ipc.Client, opts ...ipc.CallOpt) ([]signature.Interface, error) {
sm.Lock()
defer sm.Unlock()
if entry := sm.cache[name]; entry != nil && !entry.expired() {
entry.lastAccessed = time.Now()
return entry.sig, nil
}
// Fetch from the remote server.
sig, err := reserved.Signature(ctx, client, name, opts...)
if err != nil {
return nil, verror2.Make(verror2.NoServers, ctx, name, err)
}
// Add to the cache.
sm.cache[name] = &cacheEntry{
sig: sig,
lastAccessed: time.Now(),
}
return sig, nil
}
// FlushCacheEntry removes the cached signature for the given name
func (sm *signatureManager) FlushCacheEntry(name string) {
delete(sm.cache, name)
}