github.com/igggame/nebulas-go@v2.1.0+incompatible/storage/disk_storage.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package storage
    20  
    21  import (
    22  	"sync"
    23  
    24  	"github.com/nebulasio/go-nebulas/util/byteutils"
    25  
    26  	"github.com/syndtr/goleveldb/leveldb"
    27  	"github.com/syndtr/goleveldb/leveldb/filter"
    28  	"github.com/syndtr/goleveldb/leveldb/opt"
    29  )
    30  
    31  // DiskStorage the nodes in trie.
    32  type DiskStorage struct {
    33  	db          *leveldb.DB
    34  	enableBatch bool
    35  	mutex       sync.Mutex
    36  	batchOpts   map[string]*batchOpt
    37  }
    38  
    39  type batchOpt struct {
    40  	key     []byte
    41  	value   []byte
    42  	deleted bool
    43  }
    44  
    45  // NewDiskStorage init a storage
    46  func NewDiskStorage(path string) (*DiskStorage, error) {
    47  	db, err := leveldb.OpenFile(path, &opt.Options{
    48  		OpenFilesCacheCapacity: 500,
    49  		BlockCacheCapacity:     8 * opt.MiB,
    50  		BlockSize:              4 * opt.MiB,
    51  		Filter:                 filter.NewBloomFilter(10),
    52  	})
    53  
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	return &DiskStorage{
    59  		db:          db,
    60  		enableBatch: false,
    61  		batchOpts:   make(map[string]*batchOpt),
    62  	}, nil
    63  }
    64  
    65  // Get return value to the key in Storage
    66  func (storage *DiskStorage) Get(key []byte) ([]byte, error) {
    67  	// if storage.enableBatch {
    68  	// 	storage.mutex.Lock()
    69  	// 	defer storage.mutex.Unlock()
    70  
    71  	// 	opt := storage.batchOpts[byteutils.Hex(key)]
    72  	// 	if opt != nil {
    73  	// 		if opt.deleted {
    74  	// 			return nil, ErrKeyNotFound
    75  	// 		}
    76  	// 		return opt.value, nil
    77  	// 	}
    78  	// }
    79  
    80  	value, err := storage.db.Get(key, nil)
    81  	if err != nil && err == leveldb.ErrNotFound {
    82  		return nil, ErrKeyNotFound
    83  	}
    84  
    85  	return value, err
    86  }
    87  
    88  // Put put the key-value entry to Storage
    89  func (storage *DiskStorage) Put(key []byte, value []byte) error {
    90  	if storage.enableBatch {
    91  		storage.mutex.Lock()
    92  		defer storage.mutex.Unlock()
    93  
    94  		storage.batchOpts[byteutils.Hex(key)] = &batchOpt{
    95  			key:     key,
    96  			value:   value,
    97  			deleted: false,
    98  		}
    99  
   100  		return nil
   101  	}
   102  
   103  	return storage.db.Put(key, value, nil)
   104  }
   105  
   106  // Del delete the key in Storage.
   107  func (storage *DiskStorage) Del(key []byte) error {
   108  	if storage.enableBatch {
   109  		storage.mutex.Lock()
   110  		defer storage.mutex.Unlock()
   111  
   112  		storage.batchOpts[byteutils.Hex(key)] = &batchOpt{
   113  			key:     key,
   114  			deleted: true,
   115  		}
   116  
   117  		return nil
   118  	}
   119  
   120  	return storage.db.Delete(key, nil)
   121  }
   122  
   123  // Close levelDB
   124  func (storage *DiskStorage) Close() error {
   125  	return storage.db.Close()
   126  }
   127  
   128  // EnableBatch enable batch write.
   129  func (storage *DiskStorage) EnableBatch() {
   130  	storage.enableBatch = true
   131  }
   132  
   133  // Flush write and flush pending batch write.
   134  func (storage *DiskStorage) Flush() error {
   135  	storage.mutex.Lock()
   136  	defer storage.mutex.Unlock()
   137  
   138  	if !storage.enableBatch {
   139  		return nil
   140  	}
   141  
   142  	batch := new(leveldb.Batch)
   143  	for _, opt := range storage.batchOpts {
   144  		if opt.deleted {
   145  			batch.Delete(opt.key)
   146  		} else {
   147  			batch.Put(opt.key, opt.value)
   148  		}
   149  	}
   150  	storage.batchOpts = make(map[string]*batchOpt)
   151  
   152  	return storage.db.Write(batch, nil)
   153  }
   154  
   155  // DisableBatch disable batch write.
   156  func (storage *DiskStorage) DisableBatch() {
   157  	storage.mutex.Lock()
   158  	defer storage.mutex.Unlock()
   159  
   160  	storage.batchOpts = make(map[string]*batchOpt)
   161  	storage.enableBatch = false
   162  }