step-7
parent
2c4f868371
commit
2da67f7bac
|
@ -19,6 +19,7 @@ type ErrorMsg struct{
|
||||||
const (
|
const (
|
||||||
REQUEST_BODY_SIZE = 1024 * 30
|
REQUEST_BODY_SIZE = 1024 * 30
|
||||||
MAX_REQUEST_COUNT = 20
|
MAX_REQUEST_COUNT = 20
|
||||||
|
BIN_LIFETIME = 60 * 60 * 24 * 2
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -26,7 +27,7 @@ type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetApi(config *Config) *martini.ClassicMartini {
|
func GetApi(config *Config) *martini.ClassicMartini {
|
||||||
storage := NewMemoryStorage(MAX_REQUEST_COUNT)
|
storage := NewMemoryStorage(MAX_REQUEST_COUNT, BIN_LIFETIME)
|
||||||
store := sessions.NewCookieStore([]byte(config.SessionSecret))
|
store := sessions.NewCookieStore([]byte(config.SessionSecret))
|
||||||
|
|
||||||
api := martini.Classic()
|
api := martini.Classic()
|
||||||
|
|
|
@ -3,12 +3,14 @@ package skimmer
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MemoryStorage struct {
|
type MemoryStorage struct {
|
||||||
BaseStorage
|
BaseStorage
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
binRecords map[string]*BinRecord
|
binRecords map[string]*BinRecord
|
||||||
|
cleanTimer *time.Timer
|
||||||
}
|
}
|
||||||
|
|
||||||
type BinRecord struct {
|
type BinRecord struct {
|
||||||
|
@ -30,13 +32,40 @@ func (binRecord *BinRecord) ShrinkRequests(size int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMemoryStorage(maxRequests int) *MemoryStorage {
|
func NewMemoryStorage(maxRequests int, binLifetime int64) *MemoryStorage {
|
||||||
return &MemoryStorage{
|
storage := &MemoryStorage{
|
||||||
BaseStorage{
|
BaseStorage{
|
||||||
maxRequests: maxRequests,
|
maxRequests: maxRequests,
|
||||||
|
binLifetime: binLifetime,
|
||||||
},
|
},
|
||||||
sync.RWMutex{},
|
sync.RWMutex{},
|
||||||
map[string]*BinRecord{},
|
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.requestMap[req.Id] = req
|
||||||
binRecord.ShrinkRequests(storage.maxRequests)
|
binRecord.ShrinkRequests(storage.maxRequests)
|
||||||
binRecord.bin.RequestCount = len(binRecord.requests)
|
binRecord.bin.RequestCount = len(binRecord.requests)
|
||||||
|
binRecord.bin.Updated = time.Now().Unix()
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -5,16 +5,17 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func getMemoryStorage() *MemoryStorage {
|
func getMemoryStorage() *MemoryStorage {
|
||||||
return NewMemoryStorage(REQUEST_BODY_SIZE)
|
return NewMemoryStorage(REQUEST_BODY_SIZE, BIN_LIFETIME)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewMemoryStorage(t *testing.T) {
|
func TestNewMemoryStorage(t *testing.T) {
|
||||||
maxRequests := 20
|
maxRequests := 20
|
||||||
storage := NewMemoryStorage(maxRequests)
|
storage := NewMemoryStorage(maxRequests, BIN_LIFETIME)
|
||||||
|
|
||||||
assert.Equal(t, storage.maxRequests, maxRequests)
|
assert.Equal(t, storage.maxRequests, maxRequests)
|
||||||
assert.NotNil(t, storage.binRecords)
|
assert.NotNil(t, storage.binRecords)
|
||||||
|
@ -103,7 +104,7 @@ func TestLookupBins(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateRequest(t *testing.T) {
|
func TestCreateRequest(t *testing.T) {
|
||||||
storage := NewMemoryStorage(2)
|
storage := NewMemoryStorage(2, BIN_LIFETIME)
|
||||||
bin := NewBin()
|
bin := NewBin()
|
||||||
storage.CreateBin(bin)
|
storage.CreateBin(bin)
|
||||||
httpRequest, _ := http.NewRequest("GET", "/", bytes.NewBuffer([]byte("body")))
|
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()
|
||||||
|
}
|
||||||
|
|
|
@ -12,4 +12,5 @@ type Storage interface {
|
||||||
|
|
||||||
type BaseStorage struct {
|
type BaseStorage struct {
|
||||||
maxRequests int
|
maxRequests int
|
||||||
|
binLifetime int64
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue