blob: cfb254cbb63a7ccf5e48c40ce901288b44b413ea [file] [log] [blame]
Jatin Lodhia45a1fa82015-06-18 11:51:04 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package watchable
6
7import (
8 "fmt"
9 "io/ioutil"
Raja Daoudd4543072015-06-30 11:15:55 -070010 "math"
Jatin Lodhia101bd212015-06-22 13:35:53 -070011 "time"
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070012
13 "v.io/syncbase/x/ref/services/syncbase/clock"
14 "v.io/syncbase/x/ref/services/syncbase/store"
15 "v.io/syncbase/x/ref/services/syncbase/store/leveldb"
16 "v.io/syncbase/x/ref/services/syncbase/store/memstore"
17 "v.io/v23/vom"
18)
19
20// This file provides utility methods for tests related to watchable store.
21
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070022////////////////////////////////////////////////////////////
23// Functions for store creation/cleanup
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070024
Jatin Lodhia101bd212015-06-22 13:35:53 -070025// createStore returns a store along with a function to destroy the store
26// once it is no longer needed.
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070027func createStore() (store.Store, func()) {
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070028 var st store.Store
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070029 // With Memstore, TestReadWriteRandom is slow with ManagedPrefixes=nil since
30 // every watchable.Store.Get() takes a snapshot, and memstore snapshots are
31 // relatively expensive since the entire data map is copied. LevelDB snapshots
32 // are cheap, so with LevelDB ManagedPrefixes=nil is still reasonably fast.
33 if false {
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070034 st = memstore.New()
35 return st, func() {
36 st.Close()
37 }
38 } else {
Sergey Rogulenkod1ecd262015-08-14 12:39:55 -070039 path := getPath()
40 st = createLevelDB(path)
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070041 return st, func() {
Sergey Rogulenkod1ecd262015-08-14 12:39:55 -070042 destroyLevelDB(st, path)
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070043 }
44 }
45}
46
47func getPath() string {
48 path, err := ioutil.TempDir("", "syncbase_leveldb")
49 if err != nil {
50 panic(fmt.Sprintf("can't create temp dir: %v", err))
51 }
52 return path
53}
54
55func createLevelDB(path string) store.Store {
Adam Sadovskyb6a5aa32015-07-07 13:05:26 -070056 st, err := leveldb.Open(path, leveldb.OpenOptions{CreateIfMissing: true, ErrorIfExists: true})
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070057 if err != nil {
58 panic(fmt.Sprintf("can't open db at %v: %v", path, err))
59 }
60 return st
61}
62
63func destroyLevelDB(st store.Store, path string) {
64 st.Close()
65 if err := leveldb.Destroy(path); err != nil {
66 panic(fmt.Sprintf("can't destroy db at %v: %v", path, err))
67 }
68}
69
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070070////////////////////////////////////////////////////////////
71// Functions related to watchable store
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070072
73func getSeq(st Store) uint64 {
74 wst := st.(*wstore)
75 return wst.seq
76}
77
78func setMockSystemClock(st Store, mockClock clock.SystemClock) {
79 wst := st.(*wstore)
80 wst.clock.SetSystemClock(mockClock)
81}
82
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070083// logEntryReader provides a stream-like interface to scan over the log entries
Raja Daoudd4543072015-06-30 11:15:55 -070084// of a single batch, starting for a given sequence number. It opens a stream
85// that scans the log from the sequence number given. It stops after reading
86// the last entry in that batch (indicated by a false Continued flag).
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070087type logEntryReader struct {
Raja Daoudd4543072015-06-30 11:15:55 -070088 stream store.Stream // scan stream on the store Database
89 done bool // true after reading the last batch entry
90 key string // key of most recent log entry read
91 entry LogEntry // most recent log entry read
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070092}
93
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070094func newLogEntryReader(st store.Store, seq uint64) *logEntryReader {
Sergey Rogulenko40402b52015-08-10 15:09:48 -070095 stream := st.Scan([]byte(logEntryKey(seq)), []byte(logEntryKey(math.MaxUint64)))
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070096 return &logEntryReader{stream: stream}
Jatin Lodhia45a1fa82015-06-18 11:51:04 -070097}
98
Adam Sadovsky4dcc3532015-07-31 13:54:19 -070099func (ler *logEntryReader) Advance() bool {
Raja Daoudd4543072015-06-30 11:15:55 -0700100 if ler.done {
101 return false
102 }
103
104 if ler.stream.Advance() {
105 ler.key = string(ler.stream.Key(nil))
106 if err := vom.Decode(ler.stream.Value(nil), &ler.entry); err != nil {
107 panic(fmt.Errorf("Failed to decode LogEntry for key: %q", ler.key))
108 }
109 if ler.entry.Continued == false {
110 ler.done = true
111 }
112 return true
113 }
114
115 ler.key = ""
116 ler.entry = LogEntry{}
117 return false
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700118}
119
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700120func (ler *logEntryReader) GetEntry() (string, LogEntry) {
Raja Daoudd4543072015-06-30 11:15:55 -0700121 return ler.key, ler.entry
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700122}
123
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700124////////////////////////////////////////////////////////////
125// Clock related utility code
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700126
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700127type mockSystemClock struct {
Jatin Lodhia101bd212015-06-22 13:35:53 -0700128 time time.Time // current time returned by call to Now()
129 increment time.Duration // how much to increment the clock by for subsequent calls to Now()
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700130}
131
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700132func newMockSystemClock(firstTimestamp time.Time, increment time.Duration) *mockSystemClock {
133 return &mockSystemClock{
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700134 time: firstTimestamp,
135 increment: increment,
136 }
137}
138
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700139func (sc *mockSystemClock) Now() time.Time {
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700140 now := sc.time
Jatin Lodhia101bd212015-06-22 13:35:53 -0700141 sc.time = sc.time.Add(sc.increment)
Jatin Lodhia45a1fa82015-06-18 11:51:04 -0700142 return now
143}
144
Adam Sadovsky4dcc3532015-07-31 13:54:19 -0700145var _ clock.SystemClock = (*mockSystemClock)(nil)