github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/sorted/sqlkv/sqlkv.go (about) 1 /* 2 Copyright 2012 The Camlistore Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package sqlkv implements the sorted.KeyValue interface using an *sql.DB. 18 package sqlkv 19 20 import ( 21 "database/sql" 22 "errors" 23 "fmt" 24 "log" 25 "regexp" 26 "sync" 27 28 "camlistore.org/pkg/leak" 29 "camlistore.org/pkg/sorted" 30 ) 31 32 // KeyValue implements the sorted.KeyValue interface using an *sql.DB. 33 type KeyValue struct { 34 DB *sql.DB 35 36 // SetFunc is an optional func to use when REPLACE INTO does not exist 37 SetFunc func(*sql.DB, string, string) error 38 BatchSetFunc func(*sql.Tx, string, string) error 39 40 // PlaceHolderFunc optionally replaces ? placeholders with the right ones for the rdbms 41 // in use 42 PlaceHolderFunc func(string) string 43 44 // Serial determines whether a Go-level mutex protects DB from 45 // concurrent access. This isn't perfect and exists just for 46 // SQLite, whose driver likes to return "the database is 47 // locked" (camlistore.org/issue/114), so this keeps some 48 // pressure off. But we still trust SQLite to deal with 49 // concurrency in most cases. 50 Serial bool 51 52 mu sync.Mutex // the mutex used, if Serial is set 53 } 54 55 func (kv *KeyValue) sql(v string) string { 56 if f := kv.PlaceHolderFunc; f != nil { 57 return f(v) 58 } 59 return v 60 } 61 62 type batchTx struct { 63 tx *sql.Tx 64 err error // sticky 65 66 // SetFunc is an optional func to use when REPLACE INTO does not exist 67 SetFunc func(*sql.Tx, string, string) error 68 69 // PlaceHolderFunc optionally replaces ? placeholders with the right ones for the rdbms 70 // in use 71 PlaceHolderFunc func(string) string 72 } 73 74 func (b *batchTx) sql(v string) string { 75 if f := b.PlaceHolderFunc; f != nil { 76 return f(v) 77 } 78 return v 79 } 80 81 func (b *batchTx) Set(key, value string) { 82 if b.err != nil { 83 return 84 } 85 if b.SetFunc != nil { 86 b.err = b.SetFunc(b.tx, key, value) 87 return 88 } 89 _, b.err = b.tx.Exec(b.sql("REPLACE INTO rows (k, v) VALUES (?, ?)"), key, value) 90 } 91 92 func (b *batchTx) Delete(key string) { 93 if b.err != nil { 94 return 95 } 96 _, b.err = b.tx.Exec(b.sql("DELETE FROM rows WHERE k=?"), key) 97 } 98 99 func (kv *KeyValue) BeginBatch() sorted.BatchMutation { 100 if kv.Serial { 101 kv.mu.Lock() 102 } 103 tx, err := kv.DB.Begin() 104 return &batchTx{ 105 tx: tx, 106 err: err, 107 SetFunc: kv.BatchSetFunc, 108 PlaceHolderFunc: kv.PlaceHolderFunc, 109 } 110 } 111 112 func (kv *KeyValue) CommitBatch(b sorted.BatchMutation) error { 113 if kv.Serial { 114 defer kv.mu.Unlock() 115 } 116 bt, ok := b.(*batchTx) 117 if !ok { 118 return fmt.Errorf("wrong BatchMutation type %T", b) 119 } 120 if bt.err != nil { 121 return bt.err 122 } 123 return bt.tx.Commit() 124 } 125 126 func (kv *KeyValue) Get(key string) (value string, err error) { 127 if kv.Serial { 128 kv.mu.Lock() 129 defer kv.mu.Unlock() 130 } 131 err = kv.DB.QueryRow(kv.sql("SELECT v FROM rows WHERE k=?"), key).Scan(&value) 132 if err == sql.ErrNoRows { 133 err = sorted.ErrNotFound 134 } 135 return 136 } 137 138 func (kv *KeyValue) Set(key, value string) error { 139 if kv.Serial { 140 kv.mu.Lock() 141 defer kv.mu.Unlock() 142 } 143 if kv.SetFunc != nil { 144 return kv.SetFunc(kv.DB, key, value) 145 } 146 _, err := kv.DB.Exec(kv.sql("REPLACE INTO rows (k, v) VALUES (?, ?)"), key, value) 147 return err 148 } 149 150 func (kv *KeyValue) Delete(key string) error { 151 if kv.Serial { 152 kv.mu.Lock() 153 defer kv.mu.Unlock() 154 } 155 _, err := kv.DB.Exec(kv.sql("DELETE FROM rows WHERE k=?"), key) 156 return err 157 } 158 159 func (kv *KeyValue) Wipe() error { 160 if kv.Serial { 161 kv.mu.Lock() 162 defer kv.mu.Unlock() 163 } 164 _, err := kv.DB.Exec(kv.sql("DELETE FROM rows")) 165 return err 166 } 167 168 func (kv *KeyValue) Close() error { return kv.DB.Close() } 169 170 func (kv *KeyValue) Find(start, end string) sorted.Iterator { 171 if kv.Serial { 172 kv.mu.Lock() 173 defer kv.mu.Unlock() 174 } 175 var rows *sql.Rows 176 var err error 177 if end == "" { 178 rows, err = kv.DB.Query(kv.sql("SELECT k, v FROM rows WHERE k >= ? ORDER BY k "), start) 179 } else { 180 rows, err = kv.DB.Query(kv.sql("SELECT k, v FROM rows WHERE k >= ? AND k < ? ORDER BY k "), start, end) 181 } 182 if err != nil { 183 log.Printf("unexpected query error: %v", err) 184 return &iter{err: err} 185 } 186 187 it := &iter{ 188 kv: kv, 189 rows: rows, 190 closeCheck: leak.NewChecker(), 191 } 192 return it 193 } 194 195 var wordThenPunct = regexp.MustCompile(`^\w+\W$`) 196 197 // iter is a iterator over sorted key/value pairs in rows. 198 type iter struct { 199 kv *KeyValue 200 end string // optional end bound 201 err error // accumulated error, returned at Close 202 203 closeCheck *leak.Checker 204 205 rows *sql.Rows // if non-nil, the rows we're reading from 206 207 key sql.RawBytes 208 val sql.RawBytes 209 skey, sval *string // if non-nil, it's been stringified 210 } 211 212 var errClosed = errors.New("sqlkv: Iterator already closed") 213 214 func (t *iter) KeyBytes() []byte { return t.key } 215 func (t *iter) Key() string { 216 if t.skey != nil { 217 return *t.skey 218 } 219 str := string(t.key) 220 t.skey = &str 221 return str 222 } 223 224 func (t *iter) ValueBytes() []byte { return t.val } 225 func (t *iter) Value() string { 226 if t.sval != nil { 227 return *t.sval 228 } 229 str := string(t.val) 230 t.sval = &str 231 return str 232 } 233 234 func (t *iter) Close() error { 235 t.closeCheck.Close() 236 if t.rows != nil { 237 t.rows.Close() 238 t.rows = nil 239 } 240 err := t.err 241 t.err = errClosed 242 return err 243 } 244 245 func (t *iter) Next() bool { 246 if t.err != nil { 247 return false 248 } 249 t.skey, t.sval = nil, nil 250 if !t.rows.Next() { 251 return false 252 } 253 t.err = t.rows.Scan(&t.key, &t.val) 254 if t.err != nil { 255 log.Printf("unexpected Scan error: %v", t.err) 256 return false 257 } 258 return true 259 }