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  }