Browse code

Vendoring boltdb @fff57c100

Signed-off-by: Alessandro Boch <aboch@docker.com>

Alessandro Boch authored on 2016/09/16 02:53:48
Showing 12 changed files
... ...
@@ -88,7 +88,7 @@ clone git github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1
88 88
 clone git github.com/coreos/etcd 3a49cbb769ebd8d1dd25abb1e83386e9883a5707
89 89
 clone git github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
90 90
 clone git github.com/hashicorp/consul v0.5.2
91
-clone git github.com/boltdb/bolt v1.2.1
91
+clone git github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
92 92
 clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
93 93
 
94 94
 # get graph and distribution packages
... ...
@@ -1,4 +1,4 @@
1
-Bolt [![Coverage Status](https://coveralls.io/repos/boltdb/bolt/badge.svg?branch=master)](https://coveralls.io/r/boltdb/bolt?branch=master) [![GoDoc](https://godoc.org/github.com/boltdb/bolt?status.svg)](https://godoc.org/github.com/boltdb/bolt) ![Version](https://img.shields.io/badge/version-1.0-green.svg)
1
+Bolt [![Coverage Status](https://coveralls.io/repos/boltdb/bolt/badge.svg?branch=master)](https://coveralls.io/r/boltdb/bolt?branch=master) [![GoDoc](https://godoc.org/github.com/boltdb/bolt?status.svg)](https://godoc.org/github.com/boltdb/bolt) ![Version](https://img.shields.io/badge/version-1.2.1-green.svg)
2 2
 ====
3 3
 
4 4
 Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas]
... ...
@@ -15,11 +15,11 @@ and setting values. That's it.
15 15
 
16 16
 ## Project Status
17 17
 
18
-Bolt is stable and the API is fixed. Full unit test coverage and randomized
19
-black box testing are used to ensure database consistency and thread safety.
20
-Bolt is currently in high-load production environments serving databases as
21
-large as 1TB. Many companies such as Shopify and Heroku use Bolt-backed
22
-services every day.
18
+Bolt is stable, the API is fixed, and the file format is fixed. Full unit
19
+test coverage and randomized black box testing are used to ensure database
20
+consistency and thread safety. Bolt is currently in high-load production
21
+environments serving databases as large as 1TB. Many companies such as
22
+Shopify and Heroku use Bolt-backed services every day.
23 23
 
24 24
 ## Table of Contents
25 25
 
... ...
@@ -209,7 +209,7 @@ and then safely close your transaction if an error is returned. This is the
209 209
 recommended way to use Bolt transactions.
210 210
 
211 211
 However, sometimes you may want to manually start and end your transactions.
212
-You can use the `Tx.Begin()` function directly but **please** be sure to close
212
+You can use the `DB.Begin()` function directly but **please** be sure to close
213 213
 the transaction.
214 214
 
215 215
 ```go
... ...
@@ -313,7 +313,7 @@ func (s *Store) CreateUser(u *User) error {
313 313
         // Generate ID for the user.
314 314
         // This returns an error only if the Tx is closed or not writeable.
315 315
         // That can't happen in an Update() call so I ignore the error check.
316
-        id, _ = b.NextSequence()
316
+        id, _ := b.NextSequence()
317 317
         u.ID = int(id)
318 318
 
319 319
         // Marshal user data into bytes.
... ...
@@ -448,6 +448,10 @@ db.View(func(tx *bolt.Tx) error {
448 448
 })
449 449
 ```
450 450
 
451
+Please note that keys and values in `ForEach()` are only valid while
452
+the transaction is open. If you need to use a key or value outside of
453
+the transaction, you must use `copy()` to copy it to another byte
454
+slice.
451 455
 
452 456
 ### Nested buckets
453 457
 
... ...
@@ -557,7 +561,7 @@ if err != nil {
557 557
 Bolt is able to run on mobile devices by leveraging the binding feature of the
558 558
 [gomobile](https://github.com/golang/mobile) tool. Create a struct that will
559 559
 contain your database logic and a reference to a `*bolt.DB` with a initializing
560
-contstructor that takes in a filepath where the database file will be stored.
560
+constructor that takes in a filepath where the database file will be stored.
561 561
 Neither Android nor iOS require extra permissions or cleanup from using this method.
562 562
 
563 563
 ```go
... ...
@@ -807,6 +811,7 @@ them via pull request.
807 807
 
808 808
 Below is a list of public, open source projects that use Bolt:
809 809
 
810
+* [BoltDbWeb](https://github.com/evnix/boltdbweb) - A web based GUI for BoltDB files.
810 811
 * [Operation Go: A Routine Mission](http://gocode.io) - An online programming game for Golang using Bolt for user accounts and a leaderboard.
811 812
 * [Bazil](https://bazil.org/) - A file system that lets your data reside where it is most convenient for it to reside.
812 813
 * [DVID](https://github.com/janelia-flyem/dvid) - Added Bolt as optional storage engine and testing it against Basho-tuned leveldb.
... ...
@@ -825,7 +830,6 @@ Below is a list of public, open source projects that use Bolt:
825 825
 * [cayley](https://github.com/google/cayley) - Cayley is an open-source graph database using Bolt as optional backend.
826 826
 * [bleve](http://www.blevesearch.com/) - A pure Go search engine similar to ElasticSearch that uses Bolt as the default storage backend.
827 827
 * [tentacool](https://github.com/optiflows/tentacool) - REST api server to manage system stuff (IP, DNS, Gateway...) on a linux server.
828
-* [SkyDB](https://github.com/skydb/sky) - Behavioral analytics database.
829 828
 * [Seaweed File System](https://github.com/chrislusf/seaweedfs) - Highly scalable distributed key~file system with O(1) disk read.
830 829
 * [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics.
831 830
 * [Freehold](http://tshannon.bitbucket.org/freehold/) - An open, secure, and lightweight platform for your files and data.
... ...
@@ -842,9 +846,12 @@ Below is a list of public, open source projects that use Bolt:
842 842
 * [Go Report Card](https://goreportcard.com/) - Go code quality report cards as a (free and open source) service.
843 843
 * [Boltdb Boilerplate](https://github.com/bobintornado/boltdb-boilerplate) - Boilerplate wrapper around bolt aiming to make simple calls one-liners.
844 844
 * [lru](https://github.com/crowdriff/lru) - Easy to use Bolt-backed Least-Recently-Used (LRU) read-through cache with chainable remote stores.
845
-* [Storm](https://github.com/asdine/storm) - A simple ORM around BoltDB.
845
+* [Storm](https://github.com/asdine/storm) - Simple and powerful ORM for BoltDB.
846 846
 * [GoWebApp](https://github.com/josephspurrier/gowebapp) - A basic MVC web application in Go using BoltDB.
847 847
 * [SimpleBolt](https://github.com/xyproto/simplebolt) - A simple way to use BoltDB. Deals mainly with strings.
848 848
 * [Algernon](https://github.com/xyproto/algernon) - A HTTP/2 web server with built-in support for Lua. Uses BoltDB as the default database backend.
849
+* [MuLiFS](https://github.com/dankomiocevic/mulifs) - Music Library Filesystem creates a filesystem to organise your music files.
850
+* [GoShort](https://github.com/pankajkhairnar/goShort) - GoShort is a URL shortener written in Golang and BoltDB for persistent key/value storage and for routing it's using high performent HTTPRouter.
851
+* [torrent](https://github.com/anacrolix/torrent) - Full-featured BitTorrent client package and utilities in Go. BoltDB is a storage backend in development.
849 852
 
850 853
 If you are using Bolt in a project please send a pull request to add it to the list.
... ...
@@ -5,3 +5,6 @@ const maxMapSize = 0x7FFFFFFF // 2GB
5 5
 
6 6
 // maxAllocSize is the size used when creating array pointers.
7 7
 const maxAllocSize = 0xFFFFFFF
8
+
9
+// Are unaligned load/stores broken on this arch?
10
+var brokenUnaligned = false
... ...
@@ -5,3 +5,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
5 5
 
6 6
 // maxAllocSize is the size used when creating array pointers.
7 7
 const maxAllocSize = 0x7FFFFFFF
8
+
9
+// Are unaligned load/stores broken on this arch?
10
+var brokenUnaligned = false
... ...
@@ -1,7 +1,28 @@
1 1
 package bolt
2 2
 
3
+import "unsafe"
4
+
3 5
 // maxMapSize represents the largest mmap size supported by Bolt.
4 6
 const maxMapSize = 0x7FFFFFFF // 2GB
5 7
 
6 8
 // maxAllocSize is the size used when creating array pointers.
7 9
 const maxAllocSize = 0xFFFFFFF
10
+
11
+// Are unaligned load/stores broken on this arch?
12
+var brokenUnaligned bool
13
+
14
+func init() {
15
+	// Simple check to see whether this arch handles unaligned load/stores
16
+	// correctly.
17
+
18
+	// ARM9 and older devices require load/stores to be from/to aligned
19
+	// addresses. If not, the lower 2 bits are cleared and that address is
20
+	// read in a jumbled up order.
21
+
22
+	// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
23
+
24
+	raw := [6]byte{0xfe, 0xef, 0x11, 0x22, 0x22, 0x11}
25
+	val := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&raw)) + 2))
26
+
27
+	brokenUnaligned = val != 0x11222211
28
+}
... ...
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
7 7
 
8 8
 // maxAllocSize is the size used when creating array pointers.
9 9
 const maxAllocSize = 0x7FFFFFFF
10
+
11
+// Are unaligned load/stores broken on this arch?
12
+var brokenUnaligned = false
... ...
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
7 7
 
8 8
 // maxAllocSize is the size used when creating array pointers.
9 9
 const maxAllocSize = 0x7FFFFFFF
10
+
11
+// Are unaligned load/stores broken on this arch?
12
+var brokenUnaligned = false
... ...
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
7 7
 
8 8
 // maxAllocSize is the size used when creating array pointers.
9 9
 const maxAllocSize = 0x7FFFFFFF
10
+
11
+// Are unaligned load/stores broken on this arch?
12
+var brokenUnaligned = false
... ...
@@ -130,9 +130,17 @@ func (b *Bucket) Bucket(name []byte) *Bucket {
130 130
 func (b *Bucket) openBucket(value []byte) *Bucket {
131 131
 	var child = newBucket(b.tx)
132 132
 
133
+	// If unaligned load/stores are broken on this arch and value is
134
+	// unaligned simply clone to an aligned byte array.
135
+	unaligned := brokenUnaligned && uintptr(unsafe.Pointer(&value[0]))&3 != 0
136
+
137
+	if unaligned {
138
+		value = cloneBytes(value)
139
+	}
140
+
133 141
 	// If this is a writable transaction then we need to copy the bucket entry.
134 142
 	// Read-only transactions can point directly at the mmap entry.
135
-	if b.tx.writable {
143
+	if b.tx.writable && !unaligned {
136 144
 		child.bucket = &bucket{}
137 145
 		*child.bucket = *(*bucket)(unsafe.Pointer(&value[0]))
138 146
 	} else {
... ...
@@ -329,6 +337,28 @@ func (b *Bucket) Delete(key []byte) error {
329 329
 	return nil
330 330
 }
331 331
 
332
+// Sequence returns the current integer for the bucket without incrementing it.
333
+func (b *Bucket) Sequence() uint64 { return b.bucket.sequence }
334
+
335
+// SetSequence updates the sequence number for the bucket.
336
+func (b *Bucket) SetSequence(v uint64) error {
337
+	if b.tx.db == nil {
338
+		return ErrTxClosed
339
+	} else if !b.Writable() {
340
+		return ErrTxNotWritable
341
+	}
342
+
343
+	// Materialize the root node if it hasn't been already so that the
344
+	// bucket will be saved during commit.
345
+	if b.rootNode == nil {
346
+		_ = b.node(b.root, nil)
347
+	}
348
+
349
+	// Increment and return the sequence.
350
+	b.bucket.sequence = v
351
+	return nil
352
+}
353
+
332 354
 // NextSequence returns an autoincrementing integer for the bucket.
333 355
 func (b *Bucket) NextSequence() (uint64, error) {
334 356
 	if b.tx.db == nil {
... ...
@@ -166,12 +166,16 @@ func (f *freelist) read(p *page) {
166 166
 	}
167 167
 
168 168
 	// Copy the list of page ids from the freelist.
169
-	ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx:count]
170
-	f.ids = make([]pgid, len(ids))
171
-	copy(f.ids, ids)
169
+	if count == 0 {
170
+		f.ids = nil
171
+	} else {
172
+		ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx:count]
173
+		f.ids = make([]pgid, len(ids))
174
+		copy(f.ids, ids)
172 175
 
173
-	// Make sure they're sorted.
174
-	sort.Sort(pgids(f.ids))
176
+		// Make sure they're sorted.
177
+		sort.Sort(pgids(f.ids))
178
+	}
175 179
 
176 180
 	// Rebuild the page cache.
177 181
 	f.reindex()
... ...
@@ -189,7 +193,9 @@ func (f *freelist) write(p *page) error {
189 189
 
190 190
 	// The page.count can only hold up to 64k elements so if we overflow that
191 191
 	// number then we handle it by putting the size in the first element.
192
-	if len(ids) < 0xFFFF {
192
+	if len(ids) == 0 {
193
+		p.count = uint16(len(ids))
194
+	} else if len(ids) < 0xFFFF {
193 195
 		p.count = uint16(len(ids))
194 196
 		copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:], ids)
195 197
 	} else {
... ...
@@ -230,7 +236,7 @@ func (f *freelist) reload(p *page) {
230 230
 
231 231
 // reindex rebuilds the free cache based on available and pending free lists.
232 232
 func (f *freelist) reindex() {
233
-	f.cache = make(map[pgid]bool)
233
+	f.cache = make(map[pgid]bool, len(f.ids))
234 234
 	for _, id := range f.ids {
235 235
 		f.cache[id] = true
236 236
 	}
... ...
@@ -201,6 +201,11 @@ func (n *node) write(p *page) {
201 201
 	}
202 202
 	p.count = uint16(len(n.inodes))
203 203
 
204
+	// Stop here if there are no items to write.
205
+	if p.count == 0 {
206
+		return
207
+	}
208
+
204 209
 	// Loop over each item and write it to the page.
205 210
 	b := (*[maxAllocSize]byte)(unsafe.Pointer(&p.ptr))[n.pageElementSize()*len(n.inodes):]
206 211
 	for i, item := range n.inodes {
... ...
@@ -62,6 +62,9 @@ func (p *page) leafPageElement(index uint16) *leafPageElement {
62 62
 
63 63
 // leafPageElements retrieves a list of leaf nodes.
64 64
 func (p *page) leafPageElements() []leafPageElement {
65
+	if p.count == 0 {
66
+		return nil
67
+	}
65 68
 	return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:]
66 69
 }
67 70
 
... ...
@@ -72,6 +75,9 @@ func (p *page) branchPageElement(index uint16) *branchPageElement {
72 72
 
73 73
 // branchPageElements retrieves a list of branch nodes.
74 74
 func (p *page) branchPageElements() []branchPageElement {
75
+	if p.count == 0 {
76
+		return nil
77
+	}
75 78
 	return ((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[:]
76 79
 }
77 80