Refactored the way views are stored with a mgiration off the old data (to be removed)

This commit is contained in:
James Mills 2020-03-25 16:01:29 +10:00
parent 7113a7bd05
commit 2c8af03164
No known key found for this signature in database
GPG key ID: AC4C014F1440EBD6
5 changed files with 165 additions and 83 deletions

View file

@ -292,21 +292,33 @@ func (a *App) pageHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
views, err := a.Store.GetViews(prefix, id) views, err := a.Store.GetViews(id)
if err != nil { if err != nil {
err := fmt.Errorf("error retrieving views for %s %s: %w", prefix, id, err) err := fmt.Errorf("error retrieving views for %s: %w", id, err)
log.Warn(err) log.Warn(err)
} }
playing.Views = views playing.Views = views
playlist := a.Library.Playlist()
// TODO: Optimize this? Bitcask has no concept of MultiGet / MGET
for _, video := range playlist {
views, err := a.Store.GetViews(video.ID)
if err != nil {
err := fmt.Errorf("error retrieving views for %s: %w", video.ID, err)
log.Warn(err)
}
video.Views = views
}
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
ctx := &struct { ctx := &struct {
Playing *media.Video Playing *media.Video
Playlist media.Playlist Playlist media.Playlist
}{ }{
Playing: playing, Playing: playing,
Playlist: a.Library.Playlist(), Playlist: playlist,
} }
a.render("index", w, ctx) a.render("index", w, ctx)
} }
@ -325,8 +337,13 @@ func (a *App) videoHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := a.Store.IncView(prefix, id); err != nil { if err := a.Store.Migrate(prefix, id); err != nil {
err := fmt.Errorf("error updating view for %s %s: %w", prefix, id, err) err := fmt.Errorf("error migrating store data: %w", err)
log.Warn(err)
}
if err := a.Store.IncViews(id); err != nil {
err := fmt.Errorf("error updating view for %s: %w", id, err)
log.Warn(err) log.Warn(err)
} }

View file

@ -23,13 +23,38 @@ func NewBitcaskStore(path string, options ...bitcask.Option) (Store, error) {
return &BitcaskStore{db: db}, nil return &BitcaskStore{db: db}, nil
} }
// Migrate ...
func (s *BitcaskStore) Migrate(collection, id string) error {
if s.db.Has([]byte(fmt.Sprintf("/views/%s/%s", collection, id))) {
oldViews, err := s.GetViews_(collection, id)
if err != nil {
err := fmt.Errorf("error getting old views for %s %s: %w", collection, id, err)
return err
}
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, uint64(oldViews))
err = s.db.Put([]byte(fmt.Sprintf("/views/%s/%s", id)), buf)
if err != nil {
err := fmt.Errorf("error storing new views for %s: %w", id, err)
return err
}
if err := s.db.Delete([]byte(fmt.Sprintf("/views/%s/%s", collection, id))); err != nil {
err := fmt.Errorf("error deleting old views for %s %s: %w", collection, id, err)
return err
}
}
return nil
}
// Close ... // Close ...
func (s *BitcaskStore) Close() error { func (s *BitcaskStore) Close() error {
return s.db.Close() return s.db.Close()
} }
// GetViews ... // GetViews_ ...
func (s *BitcaskStore) GetViews(collection, id string) (int64, error) { func (s *BitcaskStore) GetViews_(collection, id string) (int64, error) {
var views uint64 var views uint64
rawViews, err := s.db.Get([]byte(fmt.Sprintf("/views/%s/%s", collection, id))) rawViews, err := s.db.Get([]byte(fmt.Sprintf("/views/%s/%s", collection, id)))
if err != nil { if err != nil {
@ -45,9 +70,9 @@ func (s *BitcaskStore) GetViews(collection, id string) (int64, error) {
return int64(views), nil return int64(views), nil
} }
// IncView ... // IncView_ ...
func (s *BitcaskStore) IncView(collection, id string) error { func (s *BitcaskStore) IncView_(collection, id string) error {
views, err := s.GetViews(collection, id) views, err := s.GetViews_(collection, id)
if err != nil { if err != nil {
err := fmt.Errorf("error getting existing views for %s %s: %w", collection, id, err) err := fmt.Errorf("error getting existing views for %s %s: %w", collection, id, err)
return err return err
@ -64,3 +89,40 @@ func (s *BitcaskStore) IncView(collection, id string) error {
return nil return nil
} }
// GetViews ...
func (s *BitcaskStore) GetViews(id string) (int64, error) {
var views uint64
rawViews, err := s.db.Get([]byte(fmt.Sprintf("/views/%s", id)))
if err != nil {
if err != bitcask.ErrKeyNotFound {
err := fmt.Errorf("error getting views for %s: %w", id, err)
log.Error(err)
return 0, err
}
} else {
views = binary.BigEndian.Uint64(rawViews)
}
return int64(views), nil
}
// IncViews ...
func (s *BitcaskStore) IncViews(id string) error {
views, err := s.GetViews(id)
if err != nil {
err := fmt.Errorf("error getting existing views for %s: %w", id, err)
return err
}
buf := make([]byte, 8)
views++
binary.BigEndian.PutUint64(buf, uint64(views))
err = s.db.Put([]byte(fmt.Sprintf("/views/%s", id)), buf)
if err != nil {
err := fmt.Errorf("error storing updated views for %s: %w", id, err)
return err
}
return nil
}

File diff suppressed because one or more lines are too long

View file

@ -3,6 +3,9 @@ package app
// Store ... // Store ...
type Store interface { type Store interface {
Close() error Close() error
GetViews(collection, id string) (int64, error) Migrate(collection, id string) error
IncView(collection, id string) error GetViews_(collection, id string) (int64, error)
IncView_(collection, id string) error
GetViews(id string) (int64, error)
IncViews(id string) error
} }

View file

@ -20,7 +20,7 @@
<img src="/t/{{ $m.ID }}"> <img src="/t/{{ $m.ID }}">
<div> <div>
<h1>{{ $m.Title }}</h1> <h1>{{ $m.Title }}</h1>
<h2>{{ $m.Modified }}</h2> <h2>{{ $m.Views }} views • {{ $m.Modified }}</h2>
</div> </div>
</a> </a>
{{ end }} {{ end }}