gifs/api

Paddy 2014-10-17 Parent:08ec88016e2f

6:eb450538f079 Go to Latest

gifs/api/usage.go

Make UsageTracker an interface, ditch the channel interface. Stop using channels to track usage. Just call functions. Make UsageTracker an interface, so there can be multiple implementations, and create the in-memory implementation.

History
1 package api
3 import (
4 "sort"
5 "sync"
7 "code.secondbit.org/uuid.hg"
8 )
10 type UsageTracker interface {
11 TrackUpload(id uuid.ID, bytes int64) error
12 TrackDownload(id uuid.ID, bytes int64) error
13 GetUsage(id uuid.ID) (Usage, error)
14 GetTopUsages(id uuid.ID, num, offset int64) ([]Usage, error)
15 }
17 type Usage struct {
18 UserID uuid.ID
19 UploadedBytes int64
20 DownloadedBytes int64
21 UploadRequests int64
22 DownloadRequests int64
23 }
25 func (u Usage) score() float64 {
26 storageCost := .026 * float64(u.UploadedBytes) / 1073741824
27 bandwidthCost := .012 * float64(u.DownloadedBytes) / 1073741824
28 uploadReqCost := .02 * float64(u.UploadRequests) / 1000
29 downloadReqCost := .01 * float64(u.DownloadRequests) / 10000
30 return storageCost + bandwidthCost + uploadReqCost + downloadReqCost
31 }
33 type topUsages []Usage
35 func (t topUsages) Less(i, j int) bool {
36 return t[i].score() > t[j].score()
37 }
39 func (t topUsages) Swap(i, j int) {
40 t[i], t[j] = t[j], t[i]
41 }
43 func (t topUsages) Len() int {
44 return len(t)
45 }
47 type MemTracker struct {
48 usages map[string]Usage
49 sync.RWMutex
50 }
52 func NewMemTracker() *MemTracker {
53 return &MemTracker{
54 usages: map[string]Usage{},
55 }
56 }
58 func (m *MemTracker) TrackUpload(id uuid.ID, bytes int64) error {
59 m.Lock()
60 defer m.Unlock()
62 use := m.usages[id.String()]
64 use.UploadedBytes = use.UploadedBytes + bytes
65 use.UploadRequests = use.UploadRequests + 1
66 m.usages[id.String()] = use
67 return nil
68 }
70 func (m *MemTracker) TrackDownload(id uuid.ID, bytes int64) error {
71 m.Lock()
72 defer m.Unlock()
74 use := m.usages[id.String()]
76 use.DownloadedBytes = use.DownloadedBytes + bytes
77 use.DownloadRequests = use.DownloadRequests + 1
78 m.usages[id.String()] = use
79 return nil
80 }
82 func (m *MemTracker) GetUsage(id uuid.ID) (Usage, error) {
83 m.RLock()
84 defer m.RUnlock()
86 return m.usages[id.String()], nil
87 }
89 func (m *MemTracker) GetTopUsages(id uuid.ID, num, offset int64) ([]Usage, error) {
90 m.RLock()
91 defer m.RUnlock()
93 usages := []Usage{}
94 for _, usage := range m.usages {
95 usages = append(usages, usage)
96 }
97 sortedUsages := topUsages(usages)
98 sort.Sort(sortedUsages)
99 usages = []Usage(sortedUsages)
101 if int64(len(usages)) <= offset {
102 return []Usage{}, nil
103 }
104 if int64(len(usages)) > offset+num {
105 return usages[offset : offset+num], nil
106 } else {
107 return usages[offset:], nil
108 }
109 }