aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--db.go19
-rw-r--r--tx.go20
2 files changed, 36 insertions, 3 deletions
diff --git a/db.go b/db.go
index 8503665..9048f6c 100644
--- a/db.go
+++ b/db.go
@@ -36,6 +36,9 @@ const (
DefaultAllocSize = 16 * 1024 * 1024
)
+// default page size for db is set to the OS page size.
+var defaultPageSize = os.Getpagesize()
+
// DB represents a collection of buckets persisted to a file on disk.
// All data access is performed through transactions which can be obtained through the DB.
// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
@@ -107,6 +110,8 @@ type DB struct {
freelist *freelist
stats Stats
+ pagePool sync.Pool
+
batchMu sync.Mutex
batch *batch
@@ -206,6 +211,13 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
}
}
+ // Initialize page pool.
+ db.pagePool = sync.Pool{
+ New: func() interface{} {
+ return make([]byte, db.pageSize)
+ },
+ }
+
// Memory map the data file.
if err := db.mmap(options.InitialMmapSize); err != nil {
_ = db.close()
@@ -787,7 +799,12 @@ func (db *DB) meta() *meta {
// allocate returns a contiguous block of memory starting at a given page.
func (db *DB) allocate(count int) (*page, error) {
// Allocate a temporary buffer for the page.
- buf := make([]byte, count*db.pageSize)
+ var buf []byte
+ if count == 1 {
+ buf = db.pagePool.Get().([]byte)
+ } else {
+ buf = make([]byte, count*db.pageSize)
+ }
p := (*page)(unsafe.Pointer(&buf[0]))
p.overflow = uint32(count - 1)
diff --git a/tx.go b/tx.go
index b8510fd..1cfb4cd 100644
--- a/tx.go
+++ b/tx.go
@@ -473,6 +473,8 @@ func (tx *Tx) write() error {
for _, p := range tx.pages {
pages = append(pages, p)
}
+ // Clear out page cache early.
+ tx.pages = make(map[pgid]*page)
sort.Sort(pages)
// Write pages to disk in order.
@@ -517,8 +519,22 @@ func (tx *Tx) write() error {
}
}
- // Clear out page cache.
- tx.pages = make(map[pgid]*page)
+ // Put small pages back to page pool.
+ for _, p := range pages {
+ // Ignore page sizes over 1 page.
+ // These are allocated using make() instead of the page pool.
+ if int(p.overflow) != 0 {
+ continue
+ }
+
+ buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:tx.db.pageSize]
+
+ // See https://go.googlesource.com/go/+/f03c9202c43e0abb130669852082117ca50aa9b1
+ for i := range buf {
+ buf[i] = 0
+ }
+ tx.db.pagePool.Put(buf)
+ }
return nil
}