From 2da67f7baca396ec62077fbdd0fd6dd5441b9bc8 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bakhmutov Date: Thu, 6 Mar 2014 16:22:13 +0400 Subject: [PATCH] step-7 --- src/skimmer/api.go | 3 ++- src/skimmer/memory.go | 34 ++++++++++++++++++++++++++++++++-- src/skimmer/memory_test.go | 25 ++++++++++++++++++++++--- src/skimmer/storage.go | 1 + 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/skimmer/api.go b/src/skimmer/api.go index 67fe513..d1921f0 100644 --- a/src/skimmer/api.go +++ b/src/skimmer/api.go @@ -19,6 +19,7 @@ type ErrorMsg struct{ const ( REQUEST_BODY_SIZE = 1024 * 30 MAX_REQUEST_COUNT = 20 + BIN_LIFETIME = 60 * 60 * 24 * 2 ) type Config struct { @@ -26,7 +27,7 @@ type Config struct { } func GetApi(config *Config) *martini.ClassicMartini { - storage := NewMemoryStorage(MAX_REQUEST_COUNT) + storage := NewMemoryStorage(MAX_REQUEST_COUNT, BIN_LIFETIME) store := sessions.NewCookieStore([]byte(config.SessionSecret)) api := martini.Classic() diff --git a/src/skimmer/memory.go b/src/skimmer/memory.go index 3b35dd8..c81b303 100644 --- a/src/skimmer/memory.go +++ b/src/skimmer/memory.go @@ -3,12 +3,14 @@ package skimmer import ( "errors" "sync" + "time" ) type MemoryStorage struct { BaseStorage sync.RWMutex binRecords map[string]*BinRecord + cleanTimer *time.Timer } type BinRecord struct { @@ -30,13 +32,40 @@ func (binRecord *BinRecord) ShrinkRequests(size int) { } } -func NewMemoryStorage(maxRequests int) *MemoryStorage { - return &MemoryStorage{ +func NewMemoryStorage(maxRequests int, binLifetime int64) *MemoryStorage { + storage := &MemoryStorage{ BaseStorage{ maxRequests: maxRequests, + binLifetime: binLifetime, }, sync.RWMutex{}, map[string]*BinRecord{}, + &time.Timer{}, + } + return storage +} + +func (storage *MemoryStorage) StartCleaning(timeout int) { + defer func(){ + storage.cleanTimer = time.AfterFunc(time.Duration(timeout) * time.Second, func(){storage.StartCleaning(timeout)}) + }() + storage.clean() +} + +func (storage *MemoryStorage) StopCleaning() { + if storage.cleanTimer != nil { + storage.cleanTimer.Stop() + } +} + +func (storage *MemoryStorage) clean() { + storage.Lock() + defer storage.Unlock() + now := time.Now().Unix() + for name, binRecord := range storage.binRecords { + if binRecord.bin.Updated < (now - storage.binLifetime) { + delete(storage.binRecords, name) + } } } @@ -125,6 +154,7 @@ func (storage *MemoryStorage) CreateRequest(bin *Bin, req *Request) error { binRecord.requestMap[req.Id] = req binRecord.ShrinkRequests(storage.maxRequests) binRecord.bin.RequestCount = len(binRecord.requests) + binRecord.bin.Updated = time.Now().Unix() return nil } else { return err diff --git a/src/skimmer/memory_test.go b/src/skimmer/memory_test.go index ef046e1..8961aae 100644 --- a/src/skimmer/memory_test.go +++ b/src/skimmer/memory_test.go @@ -5,16 +5,17 @@ import ( "github.com/stretchr/testify/assert" "net/http" "bytes" + "time" ) func getMemoryStorage() *MemoryStorage { - return NewMemoryStorage(REQUEST_BODY_SIZE) + return NewMemoryStorage(REQUEST_BODY_SIZE, BIN_LIFETIME) } func TestNewMemoryStorage(t *testing.T) { maxRequests := 20 - storage := NewMemoryStorage(maxRequests) + storage := NewMemoryStorage(maxRequests, BIN_LIFETIME) assert.Equal(t, storage.maxRequests, maxRequests) assert.NotNil(t, storage.binRecords) @@ -103,7 +104,7 @@ func TestLookupBins(t *testing.T) { } func TestCreateRequest(t *testing.T) { - storage := NewMemoryStorage(2) + storage := NewMemoryStorage(2, BIN_LIFETIME) bin := NewBin() storage.CreateBin(bin) httpRequest, _ := http.NewRequest("GET", "/", bytes.NewBuffer([]byte("body"))) @@ -203,3 +204,21 @@ func TestLookupRequests(t *testing.T) { } } + +func TestMemoryClean(t *testing.T) { + storage := NewMemoryStorage(2, -1) + bin := NewBin() + storage.CreateBin(bin) + assert.Equal(t, storage.binRecords[bin.Name].bin, bin) + storage.clean() + assert.Equal(t, len(storage.binRecords), 0) + + storage.CreateBin(bin) + assert.Equal(t, storage.binRecords[bin.Name].bin, bin) + storage.StartCleaning(0) + assert.Equal(t, len(storage.binRecords), 0) + storage.CreateBin(bin) + time.Sleep(1 * time.Millisecond) + assert.Equal(t, len(storage.binRecords), 0) + storage.StopCleaning() +} diff --git a/src/skimmer/storage.go b/src/skimmer/storage.go index db121ae..811b1a5 100644 --- a/src/skimmer/storage.go +++ b/src/skimmer/storage.go @@ -12,4 +12,5 @@ type Storage interface { type BaseStorage struct { maxRequests int + binLifetime int64 }