Separate in-memory cache from storage drivers.

This commit is contained in:
Rohit Jnagal 2015-06-02 06:40:59 +00:00
parent 80fabb3e60
commit 1a2781819e
15 changed files with 122 additions and 242 deletions

33
cache/cache.go vendored Normal file
View File

@ -0,0 +1,33 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import info "github.com/google/cadvisor/info/v1"
type Cache interface {
AddStats(ref info.ContainerReference, stats *info.ContainerStats) error
// Read most recent stats. numStats indicates max number of stats
// returned. The returned stats must be consecutive observed stats. If
// numStats < 0, then return all stats stored in the storage. The
// returned stats should be sorted in time increasing order, i.e. Most
// recent stats should be the last.
RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error)
// Close will clear the state of the storage driver. The elements
// stored in the underlying storage may or may not be deleted depending
// on the implementation of the storage driver.
Close() error
}

View File

@ -25,16 +25,16 @@ import (
"github.com/google/cadvisor/utils"
)
// TODO(vmarmol): See about refactoring this class, we have an unecessary redirection of containerStorage and InMemoryStorage.
// containerStorage is used to store per-container information
type containerStorage struct {
// TODO(vmarmol): See about refactoring this class, we have an unecessary redirection of containerCache and InMemoryCache.
// containerCache is used to store per-container information
type containerCache struct {
ref info.ContainerReference
recentStats *utils.TimedStore
maxAge time.Duration
lock sync.RWMutex
}
func (self *containerStorage) AddStats(stats *info.ContainerStats) error {
func (self *containerCache) AddStats(stats *info.ContainerStats) error {
self.lock.Lock()
defer self.lock.Unlock()
@ -43,7 +43,7 @@ func (self *containerStorage) AddStats(stats *info.ContainerStats) error {
return nil
}
func (self *containerStorage) RecentStats(start, end time.Time, maxStats int) ([]*info.ContainerStats, error) {
func (self *containerCache) RecentStats(start, end time.Time, maxStats int) ([]*info.ContainerStats, error) {
self.lock.RLock()
defer self.lock.RUnlock()
result := self.recentStats.InTimeRange(start, end, maxStats)
@ -54,31 +54,31 @@ func (self *containerStorage) RecentStats(start, end time.Time, maxStats int) ([
return converted, nil
}
func newContainerStore(ref info.ContainerReference, maxAge time.Duration) *containerStorage {
return &containerStorage{
func newContainerStore(ref info.ContainerReference, maxAge time.Duration) *containerCache {
return &containerCache{
ref: ref,
recentStats: utils.NewTimedStore(maxAge, -1),
maxAge: maxAge,
}
}
type InMemoryStorage struct {
type InMemoryCache struct {
lock sync.RWMutex
containerStorageMap map[string]*containerStorage
containerCacheMap map[string]*containerCache
maxAge time.Duration
backend storage.StorageDriver
}
func (self *InMemoryStorage) AddStats(ref info.ContainerReference, stats *info.ContainerStats) error {
var cstore *containerStorage
func (self *InMemoryCache) AddStats(ref info.ContainerReference, stats *info.ContainerStats) error {
var cstore *containerCache
var ok bool
func() {
self.lock.Lock()
defer self.lock.Unlock()
if cstore, ok = self.containerStorageMap[ref.Name]; !ok {
if cstore, ok = self.containerCacheMap[ref.Name]; !ok {
cstore = newContainerStore(ref, self.maxAge)
self.containerStorageMap[ref.Name] = cstore
self.containerCacheMap[ref.Name] = cstore
}
}()
@ -93,13 +93,13 @@ func (self *InMemoryStorage) AddStats(ref info.ContainerReference, stats *info.C
return cstore.AddStats(stats)
}
func (self *InMemoryStorage) RecentStats(name string, start, end time.Time, maxStats int) ([]*info.ContainerStats, error) {
var cstore *containerStorage
func (self *InMemoryCache) RecentStats(name string, start, end time.Time, maxStats int) ([]*info.ContainerStats, error) {
var cstore *containerCache
var ok bool
err := func() error {
self.lock.RLock()
defer self.lock.RUnlock()
if cstore, ok = self.containerStorageMap[name]; !ok {
if cstore, ok = self.containerCacheMap[name]; !ok {
return fmt.Errorf("unable to find data for container %v", name)
}
return nil
@ -111,9 +111,9 @@ func (self *InMemoryStorage) RecentStats(name string, start, end time.Time, maxS
return cstore.RecentStats(start, end, maxStats)
}
func (self *InMemoryStorage) Close() error {
func (self *InMemoryCache) Close() error {
self.lock.Lock()
self.containerStorageMap = make(map[string]*containerStorage, 32)
self.containerCacheMap = make(map[string]*containerCache, 32)
self.lock.Unlock()
return nil
}
@ -121,9 +121,9 @@ func (self *InMemoryStorage) Close() error {
func New(
maxAge time.Duration,
backend storage.StorageDriver,
) *InMemoryStorage {
ret := &InMemoryStorage{
containerStorageMap: make(map[string]*containerStorage, 32),
) *InMemoryCache {
ret := &InMemoryCache{
containerCacheMap: make(map[string]*containerCache, 32),
maxAge: maxAge,
backend: backend,
}

View File

@ -40,58 +40,58 @@ func makeStat(i int) *info.ContainerStats {
}
}
func getRecentStats(t *testing.T, memoryStorage *InMemoryStorage, numStats int) []*info.ContainerStats {
stats, err := memoryStorage.RecentStats(containerName, zero, zero, numStats)
func getRecentStats(t *testing.T, memoryCache *InMemoryCache, numStats int) []*info.ContainerStats {
stats, err := memoryCache.RecentStats(containerName, zero, zero, numStats)
require.Nil(t, err)
return stats
}
func TestAddStats(t *testing.T) {
memoryStorage := New(60*time.Second, nil)
memoryCache := New(60*time.Second, nil)
assert := assert.New(t)
assert.Nil(memoryStorage.AddStats(containerRef, makeStat(0)))
assert.Nil(memoryStorage.AddStats(containerRef, makeStat(1)))
assert.Nil(memoryStorage.AddStats(containerRef, makeStat(2)))
assert.Nil(memoryStorage.AddStats(containerRef, makeStat(0)))
assert.Nil(memoryCache.AddStats(containerRef, makeStat(0)))
assert.Nil(memoryCache.AddStats(containerRef, makeStat(1)))
assert.Nil(memoryCache.AddStats(containerRef, makeStat(2)))
assert.Nil(memoryCache.AddStats(containerRef, makeStat(0)))
containerRef2 := info.ContainerReference{
Name: "/container2",
}
assert.Nil(memoryStorage.AddStats(containerRef2, makeStat(0)))
assert.Nil(memoryStorage.AddStats(containerRef2, makeStat(1)))
assert.Nil(memoryCache.AddStats(containerRef2, makeStat(0)))
assert.Nil(memoryCache.AddStats(containerRef2, makeStat(1)))
}
func TestRecentStatsNoRecentStats(t *testing.T) {
memoryStorage := makeWithStats(0)
memoryCache := makeWithStats(0)
_, err := memoryStorage.RecentStats(containerName, zero, zero, 60)
_, err := memoryCache.RecentStats(containerName, zero, zero, 60)
assert.NotNil(t, err)
}
// Make an instance of InMemoryStorage with n stats.
func makeWithStats(n int) *InMemoryStorage {
memoryStorage := New(60*time.Second, nil)
// Make an instance of InMemoryCache with n stats.
func makeWithStats(n int) *InMemoryCache {
memoryCache := New(60*time.Second, nil)
for i := 0; i < n; i++ {
memoryStorage.AddStats(containerRef, makeStat(i))
memoryCache.AddStats(containerRef, makeStat(i))
}
return memoryStorage
return memoryCache
}
func TestRecentStatsGetZeroStats(t *testing.T) {
memoryStorage := makeWithStats(10)
memoryCache := makeWithStats(10)
assert.Len(t, getRecentStats(t, memoryStorage, 0), 0)
assert.Len(t, getRecentStats(t, memoryCache, 0), 0)
}
func TestRecentStatsGetSomeStats(t *testing.T) {
memoryStorage := makeWithStats(10)
memoryCache := makeWithStats(10)
assert.Len(t, getRecentStats(t, memoryStorage, 5), 5)
assert.Len(t, getRecentStats(t, memoryCache, 5), 5)
}
func TestRecentStatsGetAllStats(t *testing.T) {
memoryStorage := makeWithStats(10)
memoryCache := makeWithStats(10)
assert.Len(t, getRecentStats(t, memoryStorage, -1), 10)
assert.Len(t, getRecentStats(t, memoryCache, -1), 10)
}

View File

@ -28,11 +28,11 @@ import (
"github.com/docker/docker/pkg/units"
"github.com/golang/glog"
"github.com/google/cadvisor/cache/memory"
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/info/v2"
"github.com/google/cadvisor/storage/memory"
"github.com/google/cadvisor/summary"
"github.com/google/cadvisor/utils/cpuload"
)
@ -56,7 +56,7 @@ type containerInfo struct {
type containerData struct {
handler container.ContainerHandler
info containerInfo
memoryStorage *memory.InMemoryStorage
memoryCache *memory.InMemoryCache
lock sync.Mutex
loadReader cpuload.CpuLoadReader
summaryReader *summary.StatsSummary
@ -215,8 +215,8 @@ func (c *containerData) GetProcessList() ([]v2.ProcessInfo, error) {
return processes, nil
}
func newContainerData(containerName string, memoryStorage *memory.InMemoryStorage, handler container.ContainerHandler, loadReader cpuload.CpuLoadReader, logUsage bool, collectorManager collector.CollectorManager) (*containerData, error) {
if memoryStorage == nil {
func newContainerData(containerName string, memoryCache *memory.InMemoryCache, handler container.ContainerHandler, loadReader cpuload.CpuLoadReader, logUsage bool, collectorManager collector.CollectorManager) (*containerData, error) {
if memoryCache == nil {
return nil, fmt.Errorf("nil memory storage")
}
if handler == nil {
@ -229,7 +229,7 @@ func newContainerData(containerName string, memoryStorage *memory.InMemoryStorag
cont := &containerData{
handler: handler,
memoryStorage: memoryStorage,
memoryCache: memoryCache,
housekeepingInterval: *HousekeepingInterval,
loadReader: loadReader,
logUsage: logUsage,
@ -256,7 +256,7 @@ func newContainerData(containerName string, memoryStorage *memory.InMemoryStorag
func (self *containerData) nextHousekeeping(lastHousekeeping time.Time) time.Time {
if *allowDynamicHousekeeping {
var empty time.Time
stats, err := self.memoryStorage.RecentStats(self.info.Name, empty, empty, 2)
stats, err := self.memoryCache.RecentStats(self.info.Name, empty, empty, 2)
if err != nil {
if self.allowErrorLogging() {
glog.Warningf("Failed to get RecentStats(%q) while determining the next housekeeping: %v", self.info.Name, err)
@ -311,7 +311,7 @@ func (c *containerData) housekeeping() {
if c.logUsage {
const numSamples = 60
var empty time.Time
stats, err := c.memoryStorage.RecentStats(c.info.Name, empty, empty, numSamples)
stats, err := c.memoryCache.RecentStats(c.info.Name, empty, empty, numSamples)
if err != nil {
if c.allowErrorLogging() {
glog.Infof("[%s] Failed to get recent stats for logging usage: %v", c.info.Name, err)
@ -434,7 +434,7 @@ func (c *containerData) updateStats() error {
}
return err
}
err = c.memoryStorage.AddStats(ref, stats)
err = c.memoryCache.AddStats(ref, stats)
if err != nil {
return err
}

View File

@ -22,11 +22,11 @@ import (
"testing"
"time"
"github.com/google/cadvisor/cache/memory"
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container"
info "github.com/google/cadvisor/info/v1"
itest "github.com/google/cadvisor/info/v1/test"
"github.com/google/cadvisor/storage/memory"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -34,25 +34,25 @@ import (
const containerName = "/container"
// Create a containerData instance for a test.
func setupContainerData(t *testing.T, spec info.ContainerSpec) (*containerData, *container.MockContainerHandler, *memory.InMemoryStorage) {
func setupContainerData(t *testing.T, spec info.ContainerSpec) (*containerData, *container.MockContainerHandler, *memory.InMemoryCache) {
mockHandler := container.NewMockContainerHandler(containerName)
mockHandler.On("GetSpec").Return(
spec,
nil,
)
memoryStorage := memory.New(60, nil)
ret, err := newContainerData(containerName, memoryStorage, mockHandler, nil, false, &collector.FakeCollectorManager{})
memoryCache := memory.New(60, nil)
ret, err := newContainerData(containerName, memoryCache, mockHandler, nil, false, &collector.FakeCollectorManager{})
if err != nil {
t.Fatal(err)
}
return ret, mockHandler, memoryStorage
return ret, mockHandler, memoryCache
}
// Create a containerData instance for a test and add a default GetSpec mock.
func newTestContainerData(t *testing.T) (*containerData, *container.MockContainerHandler, *memory.InMemoryStorage) {
func newTestContainerData(t *testing.T) (*containerData, *container.MockContainerHandler, *memory.InMemoryCache) {
spec := itest.GenerateRandomContainerSpec(4)
ret, mockHandler, memoryStorage := setupContainerData(t, spec)
return ret, mockHandler, memoryStorage
ret, mockHandler, memoryCache := setupContainerData(t, spec)
return ret, mockHandler, memoryCache
}
func TestUpdateSubcontainers(t *testing.T) {
@ -116,9 +116,9 @@ func TestUpdateSubcontainersWithErrorOnDeadContainer(t *testing.T) {
mockHandler.AssertExpectations(t)
}
func checkNumStats(t *testing.T, memoryStorage *memory.InMemoryStorage, numStats int) {
func checkNumStats(t *testing.T, memoryCache *memory.InMemoryCache, numStats int) {
var empty time.Time
stats, err := memoryStorage.RecentStats(containerName, empty, empty, -1)
stats, err := memoryCache.RecentStats(containerName, empty, empty, -1)
require.Nil(t, err)
assert.Len(t, stats, numStats)
}
@ -127,7 +127,7 @@ func TestUpdateStats(t *testing.T) {
statsList := itest.GenerateRandomStats(1, 4, 1*time.Second)
stats := statsList[0]
cd, mockHandler, memoryStorage := newTestContainerData(t)
cd, mockHandler, memoryCache := newTestContainerData(t)
mockHandler.On("GetStats").Return(
stats,
nil,
@ -138,7 +138,7 @@ func TestUpdateStats(t *testing.T) {
t.Fatal(err)
}
checkNumStats(t, memoryStorage, 1)
checkNumStats(t, memoryCache, 1)
mockHandler.AssertExpectations(t)
}

View File

@ -27,6 +27,7 @@ import (
"github.com/docker/libcontainer/cgroups"
"github.com/golang/glog"
"github.com/google/cadvisor/cache/memory"
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/docker"
@ -35,7 +36,6 @@ import (
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/info/v2"
"github.com/google/cadvisor/storage/memory"
"github.com/google/cadvisor/utils/cpuload"
"github.com/google/cadvisor/utils/oomparser"
"github.com/google/cadvisor/utils/sysfs"
@ -113,8 +113,8 @@ type Manager interface {
}
// New takes a memory storage and returns a new manager.
func New(memoryStorage *memory.InMemoryStorage, sysfs sysfs.SysFs) (Manager, error) {
if memoryStorage == nil {
func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs) (Manager, error) {
if memoryCache == nil {
return nil, fmt.Errorf("manager requires memory storage")
}
@ -133,7 +133,7 @@ func New(memoryStorage *memory.InMemoryStorage, sysfs sysfs.SysFs) (Manager, err
newManager := &manager{
containers: make(map[namespacedContainerName]*containerData),
quitChannels: make([]chan error, 0, 2),
memoryStorage: memoryStorage,
memoryCache: memoryCache,
fsInfo: fsInfo,
cadvisorContainer: selfContainer,
startupTime: time.Now(),
@ -169,7 +169,7 @@ type namespacedContainerName struct {
type manager struct {
containers map[namespacedContainerName]*containerData
containersLock sync.RWMutex
memoryStorage *memory.InMemoryStorage
memoryCache *memory.InMemoryCache
fsInfo fs.FsInfo
machineInfo info.MachineInfo
versionInfo info.VersionInfo
@ -412,7 +412,7 @@ func (self *manager) containerDataToContainerInfo(cont *containerData, query *in
return nil, err
}
stats, err := self.memoryStorage.RecentStats(cinfo.Name, query.Start, query.End, query.NumStats)
stats, err := self.memoryCache.RecentStats(cinfo.Name, query.Start, query.End, query.NumStats)
if err != nil {
return nil, err
}
@ -597,7 +597,7 @@ func (self *manager) getRequestedContainers(containerName string, options v2.Req
func (self *manager) GetFsInfo(label string) ([]v2.FsInfo, error) {
var empty time.Time
// Get latest data from filesystems hanging off root container.
stats, err := self.memoryStorage.RecentStats("/", empty, empty, 1)
stats, err := self.memoryCache.RecentStats("/", empty, empty, 1)
if err != nil {
return nil, err
}
@ -696,7 +696,7 @@ func (m *manager) createContainer(containerName string) error {
return err
}
logUsage := *logCadvisorUsage && containerName == m.cadvisorContainer
cont, err := newContainerData(containerName, m.memoryStorage, handler, m.loadReader, logUsage, collectorManager)
cont, err := newContainerData(containerName, m.memoryCache, handler, m.loadReader, logUsage, collectorManager)
if err != nil {
return err
}

View File

@ -22,19 +22,19 @@ import (
"testing"
"time"
"github.com/google/cadvisor/cache/memory"
"github.com/google/cadvisor/collector"
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/docker"
info "github.com/google/cadvisor/info/v1"
itest "github.com/google/cadvisor/info/v1/test"
"github.com/google/cadvisor/storage/memory"
"github.com/google/cadvisor/utils/sysfs/fakesysfs"
)
// TODO(vmarmol): Refactor these tests.
func createManagerAndAddContainers(
memoryStorage *memory.InMemoryStorage,
memoryCache *memory.InMemoryCache,
sysfs *fakesysfs.FakeSysFs,
containers []string,
f func(*container.MockContainerHandler),
@ -44,7 +44,7 @@ func createManagerAndAddContainers(
mif := &manager{
containers: make(map[namespacedContainerName]*containerData),
quitChannels: make([]chan error, 0, 2),
memoryStorage: memoryStorage,
memoryCache: memoryCache,
}
for _, name := range containers {
mockHandler := container.NewMockContainerHandler(name)
@ -53,7 +53,7 @@ func createManagerAndAddContainers(
spec,
nil,
).Once()
cont, err := newContainerData(name, memoryStorage, mockHandler, nil, false, &collector.FakeCollectorManager{})
cont, err := newContainerData(name, memoryCache, mockHandler, nil, false, &collector.FakeCollectorManager{})
if err != nil {
t.Fatal(err)
}
@ -82,10 +82,10 @@ func expectManagerWithContainers(containers []string, query *info.ContainerInfoR
infosMap[container] = itest.GenerateRandomContainerInfo(container, 4, query, 1*time.Second)
}
memoryStorage := memory.New(time.Duration(query.NumStats)*time.Second, nil)
memoryCache := memory.New(time.Duration(query.NumStats)*time.Second, nil)
sysfs := &fakesysfs.FakeSysFs{}
m := createManagerAndAddContainers(
memoryStorage,
memoryCache,
sysfs,
containers,
func(h *container.MockContainerHandler) {
@ -95,7 +95,7 @@ func expectManagerWithContainers(containers []string, query *info.ContainerInfoR
t.Error(err)
}
for _, stat := range cinfo.Stats {
err = memoryStorage.AddStats(ref, stat)
err = memoryCache.AddStats(ref, stat)
if err != nil {
t.Error(err)
}

View File

@ -260,11 +260,6 @@ func (self *bigqueryStorage) AddStats(ref info.ContainerReference, stats *info.C
return nil
}
// Recent stats is not required to be implemented by any storage driver other than the in-memory cache.
func (self *bigqueryStorage) RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error) {
return nil, nil
}
func (self *bigqueryStorage) Close() error {
self.client.Close()
self.client = nil

View File

@ -229,8 +229,3 @@ func New(machineName,
ret.readyToFlush = ret.defaultReadyToFlush
return ret, nil
}
// RecentStats is only implemented by in-memory cache storage.
func (self *influxdbStorage) RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error) {
return nil, nil
}

View File

@ -89,11 +89,6 @@ func (self *redisStorage) AddStats(ref info.ContainerReference, stats *info.Cont
return nil
}
// RecentStats is only implemented by in-memory cache storage.
func (self *redisStorage) RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error) {
return nil, nil
}
func (self *redisStorage) Close() error {
return self.conn.Close()
}

View File

@ -19,16 +19,6 @@ import info "github.com/google/cadvisor/info/v1"
type StorageDriver interface {
AddStats(ref info.ContainerReference, stats *info.ContainerStats) error
// TODO(rjnagal): RecentStats() is only required by in-memory cache
// storage. Refactor and remove from the interface.
//
// Read most recent stats. numStats indicates max number of stats
// returned. The returned stats must be consecutive observed stats. If
// numStats < 0, then return all stats stored in the storage. The
// returned stats should be sorted in time increasing order, i.e. Most
// recent stats should be the last.
RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error)
// Close will clear the state of the storage driver. The elements
// stored in the underlying storage may or may not be deleted depending
// on the implementation of the storage driver.

View File

@ -29,11 +29,6 @@ func (self *MockStorageDriver) AddStats(ref info.ContainerReference, stats *info
return args.Error(0)
}
func (self *MockStorageDriver) RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error) {
args := self.Called(containerName, numStats)
return args.Get(0).([]*info.ContainerStats), args.Error(1)
}
func (self *MockStorageDriver) Close() error {
if self.MockCloseMethod {
args := self.Called()

View File

@ -147,126 +147,3 @@ func StorageDriverFillRandomStatsFunc(
}
}
}
func StorageDriverTestRetrievePartialRecentStats(driver TestStorageDriver, t *testing.T) {
defer driver.Close()
N := 100
memTrace := make([]uint64, N)
cpuTrace := make([]uint64, N)
for i := 0; i < N; i++ {
memTrace[i] = uint64(i + 1)
cpuTrace[i] = uint64(1)
}
ref := info.ContainerReference{
Name: "container",
}
trace := buildTrace(cpuTrace, memTrace, 1*time.Second)
for _, stats := range trace {
driver.AddStats(ref, stats)
}
recentStats, err := driver.RecentStats(ref.Name, 10)
if err != nil {
t.Fatal(err)
}
if len(recentStats) == 0 {
t.Fatal("should at least store one stats")
}
if len(recentStats) > 10 {
t.Fatalf("returned %v stats, not 10.", len(recentStats))
}
actualRecentStats := trace[len(trace)-len(recentStats):]
// The returned stats should be sorted in time increasing order
for i, s := range actualRecentStats {
r := recentStats[i]
if !driver.StatsEq(s, r) {
t.Errorf("unexpected stats %+v with memory usage %v; should be %+v", r, r.Memory.Usage, s)
}
}
}
func StorageDriverTestRetrieveAllRecentStats(driver TestStorageDriver, t *testing.T) {
defer driver.Close()
N := 100
memTrace := make([]uint64, N)
cpuTrace := make([]uint64, N)
for i := 0; i < N; i++ {
memTrace[i] = uint64(i + 1)
cpuTrace[i] = uint64(1)
}
ref := info.ContainerReference{
Name: "container",
}
trace := buildTrace(cpuTrace, memTrace, 1*time.Second)
for _, stats := range trace {
driver.AddStats(ref, stats)
}
recentStats, err := driver.RecentStats(ref.Name, -1)
if err != nil {
t.Fatal(err)
}
if len(recentStats) == 0 {
t.Fatal("should at least store one stats")
}
if len(recentStats) > N {
t.Fatalf("returned %v stats, not %d.", len(recentStats), N)
}
actualRecentStats := trace[len(trace)-len(recentStats):]
// The returned stats should be sorted in time increasing order
for i, s := range actualRecentStats {
r := recentStats[i]
if !driver.StatsEq(s, r) {
t.Errorf("unexpected stats %+v with memory usage %v", r, r.Memory.Usage)
}
}
}
func StorageDriverTestNoRecentStats(driver TestStorageDriver, t *testing.T) {
defer driver.Close()
nonExistContainer := "somerandomecontainer"
stats, _ := driver.RecentStats(nonExistContainer, -1)
if len(stats) > 0 {
t.Errorf("RecentStats() returns %v stats on non exist container", len(stats))
}
}
func StorageDriverTestRetrieveZeroRecentStats(driver TestStorageDriver, t *testing.T) {
defer driver.Close()
N := 100
memTrace := make([]uint64, N)
cpuTrace := make([]uint64, N)
for i := 0; i < N; i++ {
memTrace[i] = uint64(i + 1)
cpuTrace[i] = uint64(1)
}
ref := info.ContainerReference{
Name: "container",
}
trace := buildTrace(cpuTrace, memTrace, 1*time.Second)
for _, stats := range trace {
driver.AddStats(ref, stats)
}
recentStats, err := driver.RecentStats(ref.Name, 0)
if err != nil {
t.Fatal(err)
}
if len(recentStats) > 0 {
t.Errorf("RecentStats() returns %v stats when requests for 0 stats", len(recentStats))
}
}

View File

@ -21,10 +21,10 @@ import (
"time"
"github.com/golang/glog"
"github.com/google/cadvisor/cache/memory"
"github.com/google/cadvisor/storage"
"github.com/google/cadvisor/storage/bigquery"
"github.com/google/cadvisor/storage/influxdb"
"github.com/google/cadvisor/storage/memory"
"github.com/google/cadvisor/storage/redis"
)
@ -38,8 +38,8 @@ var argDbBufferDuration = flag.Duration("storage_driver_buffer_duration", 60*tim
var storageDuration = flag.Duration("storage_duration", 2*time.Minute, "How long to keep data stored (Default: 2min).")
// Creates a memory storage with an optional backend storage option.
func NewMemoryStorage(backendStorageName string) (*memory.InMemoryStorage, error) {
var storageDriver *memory.InMemoryStorage
func NewMemoryStorage(backendStorageName string) (*memory.InMemoryCache, error) {
var storageDriver *memory.InMemoryCache
var backendStorage storage.StorageDriver
var err error
switch backendStorageName {

View File

@ -19,7 +19,7 @@ import (
)
// Manages a buffer of usage samples.
// This is similar to stats buffer in storage/memory.
// This is similar to stats buffer in cache/memory.
// The main difference is that we do not pre-allocate the buffer as most containers
// won't live that long.
type SamplesBuffer struct {