-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
zoe.go
180 lines (164 loc) · 4.11 KB
/
zoe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
Zoe is an interactive shell that allows access to a transactional non-persistent in-memory key/value store.
*/
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
/*GlobalStore holds the (global) variables*/
var GlobalStore = make(map[string]string)
/*Map string:string*/
type Map = map[string]string
/*Transaction points to a key:value store*/
type Transaction struct {
store Map // every transaction has its own local store
next *Transaction
}
/*TransactionStack is maintained as a list of active/suspended transactions */
type TransactionStack struct {
top *Transaction
size int // more meta data can be saved like Stack limit etc.
}
/*PushTransaction creates a new active transaction*/
func (ts *TransactionStack) PushTransaction() {
// Push a new Transaction, this is the current active transaction
temp := Transaction{store: make(Map)}
temp.next = ts.top
ts.top = &temp
ts.size++
}
/*PopTransaction deletes a transaction from stack*/
func (ts *TransactionStack) PopTransaction() {
// Pop the Transaction from stack, no longer active
if ts.top == nil {
// basically stack underflow
fmt.Println("ERROR: No Active Transactions")
} else {
ts.top = ts.top.next
ts.size--
}
}
/*Peek returns the active transaction*/
func (ts *TransactionStack) Peek() *Transaction {
return ts.top
}
/*RollBackTransaction clears all keys SET within a transaction*/
func (ts *TransactionStack) RollBackTransaction() {
if ts.top == nil {
fmt.Println("ERROR: No Active Transaction")
} else {
// this is optimized by the Go1.11 compiler :o
for key := range ts.top.store {
delete(ts.top.store, key)
}
}
}
/*Commit write(SET) changes to the store with TranscationStack scope
Also write changes to disk/file, if data needs to persist after the shell closes
*/
func (ts *TransactionStack) Commit() {
ActiveTransaction := ts.Peek()
if ActiveTransaction != nil {
for key, value := range ActiveTransaction.store {
GlobalStore[key] = value
if ActiveTransaction.next != nil {
// update the parent transaction
ActiveTransaction.next.store[key] = value
}
}
} else {
fmt.Println("INFO: Nothing to commit")
}
}
/*Get value of key from Store*/
func Get(key string, T *TransactionStack) {
ActiveTransaction := T.Peek()
if ActiveTransaction == nil {
if val, ok := GlobalStore[key]; ok {
fmt.Println(val)
} else {
fmt.Println(key, "not set")
}
} else {
if val, ok := ActiveTransaction.store[key]; ok {
fmt.Println(val)
} else {
fmt.Println(key, "not set")
}
}
}
/*Set key to value */
func Set(key string, value string, T *TransactionStack) {
// Get key:value store from active transaction
ActiveTransaction := T.Peek()
if ActiveTransaction == nil {
GlobalStore[key] = value
} else {
ActiveTransaction.store[key] = value
}
}
/*Count returns the number of keys that have been set to the specified value.*/
func Count(value string, T *TransactionStack) {
var count int = 0
ActiveTransaction := T.Peek()
if ActiveTransaction == nil {
for _, v := range GlobalStore {
if v == value {
count++
}
}
} else {
for _, v := range ActiveTransaction.store {
if v == value {
count++
}
}
}
fmt.Println(count)
}
/*Delete value from Store */
func Delete(key string, T *TransactionStack) {
ActiveTransaction := T.Peek()
if ActiveTransaction == nil {
delete(GlobalStore, key)
} else {
delete(ActiveTransaction.store, key)
}
fmt.Println(key, "deleted")
}
func main() {
reader := bufio.NewReader(os.Stdin)
items := &TransactionStack{}
for {
fmt.Print("> ")
text, _ := reader.ReadString('\n')
// split the text into operation strings
operation := strings.Fields(text)
switch operation[0] {
case "BEGIN":
items.PushTransaction()
case "ROLLBACK":
items.RollBackTransaction()
case "COMMIT":
items.Commit()
items.PopTransaction()
case "END":
items.PopTransaction()
case "SET":
Set(operation[1], operation[2], items)
case "GET":
Get(operation[1], items)
case "DELETE":
Delete(operation[1], items)
case "COUNT":
Count(operation[1], items)
case "STOP":
os.Exit(0)
default:
fmt.Println("ERROR: Unrecognised Operation", operation[0])
}
}
}