From 210bdcd462c09d3f8cb753260d3d9a5ceefef1e1 Mon Sep 17 00:00:00 2001 From: ivcosla Date: Tue, 20 Aug 2019 19:18:31 +0200 Subject: [PATCH] bucket only contains 2 items, should contain 3 --- pkg/app/log.go | 40 +++++++++++++++++++++++----------- pkg/app/log_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 pkg/app/log_test.go diff --git a/pkg/app/log.go b/pkg/app/log.go index d7253ea97e..203b5edcfd 100644 --- a/pkg/app/log.go +++ b/pkg/app/log.go @@ -3,9 +3,9 @@ package app import ( "bytes" "fmt" - "log" "time" + "encoding/binary" "go.etcd.io/bbolt" ) @@ -13,7 +13,7 @@ import ( type LogStore interface { // Store saves given log in db - Store(t time.Time, string) error + Store(t time.Time, s string) error // LogSince returns the logs since given timestamp. For optimal performance, // the timestamp should exist in the store (you can get it from previous logs), @@ -47,18 +47,30 @@ func newBoltDB(path, appName string) (LogStore, error) { return &boltDBappLogs{db, b}, nil } +// Store implements LogStore +func (l *boltDBappLogs) Store(t time.Time, s string) error { + parsedTime := make([]byte, 16) + binary.BigEndian.PutUint64(parsedTime, uint64(t.UnixNano())) + + return l.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket(l.bucket) + return b.Put(parsedTime, []byte(s)) + }) +} + // LogSince implements LogStore func (l *boltDBappLogs) LogsSince(t time.Time) ([]string, error) { logs := make([]string, 0) err := l.db.View(func(tx *bbolt.Tx) error { b := tx.Bucket(l.bucket) - + parsedTime := make([]byte, 16) + binary.BigEndian.PutUint64(parsedTime, uint64(t.UnixNano())) c := b.Cursor() - if k, _ := c.Seek([]byte(t.Format(time.RFC3339))); k != nil { - iterateFromKey(c, logs) + if k, _ := c.Seek(parsedTime); k != nil { + iterateFromKey(c, &logs) } else { - iterateFromBeginning(c, t, logs) + iterateFromBeginning(c, parsedTime, &logs) } return nil @@ -67,20 +79,22 @@ func (l *boltDBappLogs) LogsSince(t time.Time) ([]string, error) { return logs, err } -func iterateFromKey(c *bbolt.Cursor, logs []string) { +func iterateFromKey(c *bbolt.Cursor, logs *[]string) { for k, v := c.Next(); k != nil; k, v = c.Next() { - logs = append(logs, fmt.Sprintf("%s-%s", string(k), string(v))) + *logs = append(*logs, fmt.Sprintf("%s-%s", bytesToTime(k).UTC().Format(time.RFC3339Nano), string(v))) } } -func iterateFromBeginning(c *bbolt.Cursor, t time.Time, logs []string) { - parsedT := []byte(t.UTC().Format(time.RFC3339)) - +func iterateFromBeginning(c *bbolt.Cursor, parsedTime []byte, logs *[]string) { for k, v := c.First(); k != nil; k, v = c.Next() { - if bytes.Compare(parsedT, k) < 0 { + if bytes.Compare(parsedTime, k) < 0 { continue } - logs = append(logs, fmt.Sprintf("%s-%s", string(k), string(v))) + *logs = append(*logs, fmt.Sprintf("%s-%s", bytesToTime(k).UTC().Format(time.RFC3339Nano), string(v))) } } + +func bytesToTime(b []byte) time.Time { + return time.Unix(int64(binary.BigEndian.Uint64(b)), 0) +} diff --git a/pkg/app/log_test.go b/pkg/app/log_test.go new file mode 100644 index 0000000000..593bce4dca --- /dev/null +++ b/pkg/app/log_test.go @@ -0,0 +1,53 @@ +package app + +import ( + "os" + "time" + + "github.com/stretchr/testify/require" + "io/ioutil" + "testing" +) + +func TestLogStore(t *testing.T) { + p, err := ioutil.TempFile("", "test-db") + require.NoError(t, err) + + defer os.Remove(p.Name()) + + ls, err := newBoltDB(p.Name(), "foo") + require.NoError(t, err) + + t3, err := time.Parse(time.RFC3339, "2000-03-01T00:00:00Z") + require.NoError(t, err) + + err = ls.Store(t3, "foo") + require.NoError(t, err) + + t1, err := time.Parse(time.RFC3339, "2000-01-01T00:00:00Z") + require.NoError(t, err) + + err = ls.Store(t1, "bar") + require.NoError(t, err) + + t2, err := time.Parse(time.RFC3339, "2000-02-01T00:00:00Z") + require.NoError(t, err) + + err = ls.Store(t2, "middle") + require.NoError(t, err) + + res, err := ls.LogsSince(t1) + require.NoError(t, err) + require.Len(t, res, 2) + require.Contains(t, res[0], "middle") + require.Contains(t, res[1], "foo") + + t4, err := time.Parse(time.RFC3339, "1999-02-01T00:00:00Z") + require.NoError(t, err) + res, err = ls.LogsSince(t4) + require.NoError(t, err) + require.Len(t, res, 3) + require.Contains(t, res[0], "bar") + require.Contains(t, res[1], "middle") + require.Contains(t, res[2], "foo") +}