gifs/api

Paddy 2014-10-17 Parent:eb450538f079

7:21787ed8a185 Go to Latest

gifs/api/usage.go

Create a Dockerfile and binary. Write a Dockerfile that compiles everything and runs it. Start the binary; load a Context from etcd, and start everything running. The binary is pretty useless until we get HTTP handlers, though, obviously.

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