github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/localstore/boltdb/boltdb.go (about) 1 // Copyright 2015 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package boltdb 15 16 import ( 17 "os" 18 "path" 19 20 "github.com/insionng/yougam/libraries/boltdb/bolt" 21 "github.com/insionng/yougam/libraries/juju/errors" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/store/localstore/engine" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/util/bytes" 24 ) 25 26 var ( 27 _ engine.DB = (*db)(nil) 28 ) 29 30 var ( 31 bucketName = []byte("tidb") 32 ) 33 34 type db struct { 35 *bolt.DB 36 } 37 38 func (d *db) Get(key []byte) ([]byte, error) { 39 var value []byte 40 41 err := d.DB.View(func(tx *bolt.Tx) error { 42 b := tx.Bucket(bucketName) 43 v := b.Get(key) 44 if v == nil { 45 return errors.Trace(engine.ErrNotFound) 46 } 47 value = bytes.CloneBytes(v) 48 return nil 49 }) 50 51 return value, errors.Trace(err) 52 } 53 54 func (d *db) Seek(startKey []byte) ([]byte, []byte, error) { 55 var key, value []byte 56 err := d.DB.View(func(tx *bolt.Tx) error { 57 b := tx.Bucket(bucketName) 58 c := b.Cursor() 59 var k, v []byte 60 if startKey == nil { 61 k, v = c.First() 62 } else { 63 k, v = c.Seek(startKey) 64 } 65 if k != nil { 66 key, value = bytes.CloneBytes(k), bytes.CloneBytes(v) 67 } 68 return nil 69 }) 70 71 if err != nil { 72 return nil, nil, errors.Trace(err) 73 } 74 if key == nil { 75 return nil, nil, errors.Trace(engine.ErrNotFound) 76 } 77 return key, value, nil 78 } 79 80 func (d *db) SeekReverse(startKey []byte) ([]byte, []byte, error) { 81 var key, value []byte 82 err := d.DB.View(func(tx *bolt.Tx) error { 83 b := tx.Bucket(bucketName) 84 c := b.Cursor() 85 var k, v []byte 86 if startKey == nil { 87 k, v = c.Last() 88 } else { 89 c.Seek(startKey) 90 k, v = c.Prev() 91 } 92 if k != nil { 93 key, value = bytes.CloneBytes(k), bytes.CloneBytes(v) 94 } 95 return nil 96 }) 97 98 if err != nil { 99 return nil, nil, errors.Trace(err) 100 } 101 if key == nil { 102 return nil, nil, errors.Trace(engine.ErrNotFound) 103 } 104 return key, value, nil 105 } 106 107 func (d *db) NewBatch() engine.Batch { 108 return &batch{} 109 } 110 111 func (d *db) Commit(b engine.Batch) error { 112 bt, ok := b.(*batch) 113 if !ok { 114 return errors.Errorf("invalid batch type %T", b) 115 } 116 err := d.DB.Update(func(tx *bolt.Tx) error { 117 b := tx.Bucket(bucketName) 118 // err1 is used for passing `go tool vet --shadow` check. 119 var err1 error 120 for _, w := range bt.writes { 121 if !w.isDelete { 122 err1 = b.Put(w.key, w.value) 123 } else { 124 err1 = b.Delete(w.key) 125 } 126 127 if err1 != nil { 128 return errors.Trace(err1) 129 } 130 } 131 132 return nil 133 }) 134 return errors.Trace(err) 135 } 136 137 func (d *db) Close() error { 138 return d.DB.Close() 139 } 140 141 type write struct { 142 key []byte 143 value []byte 144 isDelete bool 145 } 146 147 type batch struct { 148 writes []write 149 } 150 151 func (b *batch) Put(key []byte, value []byte) { 152 w := write{ 153 key: append([]byte(nil), key...), 154 value: append([]byte(nil), value...), 155 } 156 b.writes = append(b.writes, w) 157 } 158 159 func (b *batch) Delete(key []byte) { 160 w := write{ 161 key: append([]byte(nil), key...), 162 value: nil, 163 isDelete: true, 164 } 165 b.writes = append(b.writes, w) 166 } 167 168 func (b *batch) Len() int { 169 return len(b.writes) 170 } 171 172 // Driver implements engine Driver. 173 type Driver struct { 174 } 175 176 // Open opens or creates a local storage database with given path. 177 func (driver Driver) Open(dbPath string) (engine.DB, error) { 178 base := path.Dir(dbPath) 179 os.MkdirAll(base, 0755) 180 181 d, err := bolt.Open(dbPath, 0600, nil) 182 if err != nil { 183 return nil, err 184 } 185 186 tx, err := d.Begin(true) 187 if err != nil { 188 return nil, err 189 } 190 191 if _, err = tx.CreateBucketIfNotExists(bucketName); err != nil { 192 tx.Rollback() 193 return nil, err 194 } 195 196 if err = tx.Commit(); err != nil { 197 return nil, err 198 } 199 200 return &db{d}, nil 201 }