github.com/xxRanger/go-ethereum@v1.8.23/swarm/storage/ldbstore.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // disk storage layer for the package bzz
    18  // DbStore implements the ChunkStore interface and is used by the FileStore as
    19  // persistent storage of chunks
    20  // it implements purging based on access count allowing for external control of
    21  // max capacity
    22  
    23  package storage
    24  
    25  import (
    26  	"archive/tar"
    27  	"bytes"
    28  	"context"
    29  	"encoding/binary"
    30  	"encoding/hex"
    31  	"errors"
    32  	"fmt"
    33  	"io"
    34  	"io/ioutil"
    35  	"sync"
    36  
    37  	"github.com/ethereum/go-ethereum/metrics"
    38  	"github.com/ethereum/go-ethereum/rlp"
    39  	"github.com/ethereum/go-ethereum/swarm/log"
    40  	"github.com/ethereum/go-ethereum/swarm/storage/mock"
    41  	"github.com/syndtr/goleveldb/leveldb"
    42  )
    43  
    44  const (
    45  	defaultGCRatio    = 10
    46  	defaultMaxGCRound = 10000
    47  	defaultMaxGCBatch = 5000
    48  
    49  	wEntryCnt  = 1 << 0
    50  	wIndexCnt  = 1 << 1
    51  	wAccessCnt = 1 << 2
    52  )
    53  
    54  var (
    55  	dbEntryCount = metrics.NewRegisteredCounter("ldbstore.entryCnt", nil)
    56  )
    57  
    58  var (
    59  	keyIndex       = byte(0)
    60  	keyAccessCnt   = []byte{2}
    61  	keyEntryCnt    = []byte{3}
    62  	keyDataIdx     = []byte{4}
    63  	keyData        = byte(6)
    64  	keyDistanceCnt = byte(7)
    65  	keySchema      = []byte{8}
    66  	keyGCIdx       = byte(9) // access to chunk data index, used by garbage collection in ascending order from first entry
    67  )
    68  
    69  var (
    70  	ErrDBClosed = errors.New("LDBStore closed")
    71  )
    72  
    73  type LDBStoreParams struct {
    74  	*StoreParams
    75  	Path string
    76  	Po   func(Address) uint8
    77  }
    78  
    79  // NewLDBStoreParams constructs LDBStoreParams with the specified values.
    80  func NewLDBStoreParams(storeparams *StoreParams, path string) *LDBStoreParams {
    81  	return &LDBStoreParams{
    82  		StoreParams: storeparams,
    83  		Path:        path,
    84  		Po:          func(k Address) (ret uint8) { return uint8(Proximity(storeparams.BaseKey, k[:])) },
    85  	}
    86  }
    87  
    88  type garbage struct {
    89  	maxRound int           // maximum number of chunks to delete in one garbage collection round
    90  	maxBatch int           // maximum number of chunks to delete in one db request batch
    91  	ratio    int           // 1/x ratio to calculate the number of chunks to gc on a low capacity db
    92  	count    int           // number of chunks deleted in running round
    93  	target   int           // number of chunks to delete in running round
    94  	batch    *dbBatch      // the delete batch
    95  	runC     chan struct{} // struct in chan means gc is NOT running
    96  }
    97  
    98  type LDBStore struct {
    99  	db *LDBDatabase
   100  
   101  	// this should be stored in db, accessed transactionally
   102  	entryCnt  uint64 // number of items in the LevelDB
   103  	accessCnt uint64 // ever-accumulating number increased every time we read/access an entry
   104  	dataIdx   uint64 // similar to entryCnt, but we only increment it
   105  	capacity  uint64
   106  	bucketCnt []uint64
   107  
   108  	hashfunc SwarmHasher
   109  	po       func(Address) uint8
   110  
   111  	batchesC chan struct{}
   112  	closed   bool
   113  	batch    *dbBatch
   114  	lock     sync.RWMutex
   115  	quit     chan struct{}
   116  	gc       *garbage
   117  
   118  	// Functions encodeDataFunc is used to bypass
   119  	// the default functionality of DbStore with
   120  	// mock.NodeStore for testing purposes.
   121  	encodeDataFunc func(chunk Chunk) []byte
   122  	// If getDataFunc is defined, it will be used for
   123  	// retrieving the chunk data instead from the local
   124  	// LevelDB database.
   125  	getDataFunc func(key Address) (data []byte, err error)
   126  }
   127  
   128  type dbBatch struct {
   129  	*leveldb.Batch
   130  	err error
   131  	c   chan struct{}
   132  }
   133  
   134  func newBatch() *dbBatch {
   135  	return &dbBatch{Batch: new(leveldb.Batch), c: make(chan struct{})}
   136  }
   137  
   138  // TODO: Instead of passing the distance function, just pass the address from which distances are calculated
   139  // to avoid the appearance of a pluggable distance metric and opportunities of bugs associated with providing
   140  // a function different from the one that is actually used.
   141  func NewLDBStore(params *LDBStoreParams) (s *LDBStore, err error) {
   142  	s = new(LDBStore)
   143  	s.hashfunc = params.Hash
   144  	s.quit = make(chan struct{})
   145  
   146  	s.batchesC = make(chan struct{}, 1)
   147  	go s.writeBatches()
   148  	s.batch = newBatch()
   149  	// associate encodeData with default functionality
   150  	s.encodeDataFunc = encodeData
   151  
   152  	s.db, err = NewLDBDatabase(params.Path)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	s.po = params.Po
   158  	s.setCapacity(params.DbCapacity)
   159  
   160  	s.bucketCnt = make([]uint64, 0x100)
   161  	for i := 0; i < 0x100; i++ {
   162  		k := make([]byte, 2)
   163  		k[0] = keyDistanceCnt
   164  		k[1] = uint8(i)
   165  		cnt, _ := s.db.Get(k)
   166  		s.bucketCnt[i] = BytesToU64(cnt)
   167  	}
   168  	data, _ := s.db.Get(keyEntryCnt)
   169  	s.entryCnt = BytesToU64(data)
   170  	data, _ = s.db.Get(keyAccessCnt)
   171  	s.accessCnt = BytesToU64(data)
   172  	data, _ = s.db.Get(keyDataIdx)
   173  	s.dataIdx = BytesToU64(data)
   174  
   175  	// set up garbage collection
   176  	s.gc = &garbage{
   177  		maxBatch: defaultMaxGCBatch,
   178  		maxRound: defaultMaxGCRound,
   179  		ratio:    defaultGCRatio,
   180  	}
   181  
   182  	s.gc.runC = make(chan struct{}, 1)
   183  	s.gc.runC <- struct{}{}
   184  
   185  	return s, nil
   186  }
   187  
   188  // MarkAccessed increments the access counter as a best effort for a chunk, so
   189  // the chunk won't get garbage collected.
   190  func (s *LDBStore) MarkAccessed(addr Address) {
   191  	s.lock.Lock()
   192  	defer s.lock.Unlock()
   193  
   194  	if s.closed {
   195  		return
   196  	}
   197  
   198  	proximity := s.po(addr)
   199  	s.tryAccessIdx(addr, proximity)
   200  }
   201  
   202  // initialize and set values for processing of gc round
   203  func (s *LDBStore) startGC(c int) {
   204  
   205  	s.gc.count = 0
   206  	// calculate the target number of deletions
   207  	if c >= s.gc.maxRound {
   208  		s.gc.target = s.gc.maxRound
   209  	} else {
   210  		s.gc.target = c / s.gc.ratio
   211  	}
   212  	s.gc.batch = newBatch()
   213  	log.Debug("startgc", "requested", c, "target", s.gc.target)
   214  }
   215  
   216  // NewMockDbStore creates a new instance of DbStore with
   217  // mockStore set to a provided value. If mockStore argument is nil,
   218  // this function behaves exactly as NewDbStore.
   219  func NewMockDbStore(params *LDBStoreParams, mockStore *mock.NodeStore) (s *LDBStore, err error) {
   220  	s, err = NewLDBStore(params)
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	// replace put and get with mock store functionality
   226  	if mockStore != nil {
   227  		s.encodeDataFunc = newMockEncodeDataFunc(mockStore)
   228  		s.getDataFunc = newMockGetDataFunc(mockStore)
   229  	}
   230  	return
   231  }
   232  
   233  type dpaDBIndex struct {
   234  	Idx    uint64
   235  	Access uint64
   236  }
   237  
   238  func BytesToU64(data []byte) uint64 {
   239  	if len(data) < 8 {
   240  		return 0
   241  	}
   242  	return binary.BigEndian.Uint64(data)
   243  }
   244  
   245  func U64ToBytes(val uint64) []byte {
   246  	data := make([]byte, 8)
   247  	binary.BigEndian.PutUint64(data, val)
   248  	return data
   249  }
   250  
   251  func getIndexKey(hash Address) []byte {
   252  	hashSize := len(hash)
   253  	key := make([]byte, hashSize+1)
   254  	key[0] = keyIndex
   255  	copy(key[1:], hash[:])
   256  	return key
   257  }
   258  
   259  func getDataKey(idx uint64, po uint8) []byte {
   260  	key := make([]byte, 10)
   261  	key[0] = keyData
   262  	key[1] = po
   263  	binary.BigEndian.PutUint64(key[2:], idx)
   264  
   265  	return key
   266  }
   267  
   268  func getGCIdxKey(index *dpaDBIndex) []byte {
   269  	key := make([]byte, 9)
   270  	key[0] = keyGCIdx
   271  	binary.BigEndian.PutUint64(key[1:], index.Access)
   272  	return key
   273  }
   274  
   275  func getGCIdxValue(index *dpaDBIndex, po uint8, addr Address) []byte {
   276  	val := make([]byte, 41) // po = 1, index.Index = 8, Address = 32
   277  	val[0] = po
   278  	binary.BigEndian.PutUint64(val[1:], index.Idx)
   279  	copy(val[9:], addr)
   280  	return val
   281  }
   282  
   283  func parseIdxKey(key []byte) (byte, []byte) {
   284  	return key[0], key[1:]
   285  }
   286  
   287  func parseGCIdxEntry(accessCnt []byte, val []byte) (index *dpaDBIndex, po uint8, addr Address) {
   288  	index = &dpaDBIndex{
   289  		Idx:    binary.BigEndian.Uint64(val[1:]),
   290  		Access: binary.BigEndian.Uint64(accessCnt),
   291  	}
   292  	po = val[0]
   293  	addr = val[9:]
   294  	return
   295  }
   296  
   297  func encodeIndex(index *dpaDBIndex) []byte {
   298  	data, _ := rlp.EncodeToBytes(index)
   299  	return data
   300  }
   301  
   302  func encodeData(chunk Chunk) []byte {
   303  	// Always create a new underlying array for the returned byte slice.
   304  	// The chunk.Address array may be used in the returned slice which
   305  	// may be changed later in the code or by the LevelDB, resulting
   306  	// that the Address is changed as well.
   307  	return append(append([]byte{}, chunk.Address()[:]...), chunk.Data()...)
   308  }
   309  
   310  func decodeIndex(data []byte, index *dpaDBIndex) error {
   311  	dec := rlp.NewStream(bytes.NewReader(data), 0)
   312  	return dec.Decode(index)
   313  }
   314  
   315  func decodeData(addr Address, data []byte) (*chunk, error) {
   316  	return NewChunk(addr, data[32:]), nil
   317  }
   318  
   319  func (s *LDBStore) collectGarbage() error {
   320  	// prevent duplicate gc from starting when one is already running
   321  	select {
   322  	case <-s.gc.runC:
   323  	default:
   324  		return nil
   325  	}
   326  
   327  	s.lock.Lock()
   328  	entryCnt := s.entryCnt
   329  	s.lock.Unlock()
   330  
   331  	metrics.GetOrRegisterCounter("ldbstore.collectgarbage", nil).Inc(1)
   332  
   333  	// calculate the amount of chunks to collect and reset counter
   334  	s.startGC(int(entryCnt))
   335  	log.Debug("collectGarbage", "target", s.gc.target, "entryCnt", entryCnt)
   336  
   337  	for s.gc.count < s.gc.target {
   338  		it := s.db.NewIterator()
   339  		ok := it.Seek([]byte{keyGCIdx})
   340  		var singleIterationCount int
   341  
   342  		// every batch needs a lock so we avoid entries changing accessidx in the meantime
   343  		s.lock.Lock()
   344  		for ; ok && (singleIterationCount < s.gc.maxBatch); ok = it.Next() {
   345  
   346  			// quit if no more access index keys
   347  			itkey := it.Key()
   348  			if (itkey == nil) || (itkey[0] != keyGCIdx) {
   349  				break
   350  			}
   351  
   352  			// get chunk data entry from access index
   353  			val := it.Value()
   354  			index, po, hash := parseGCIdxEntry(itkey[1:], val)
   355  			keyIdx := make([]byte, 33)
   356  			keyIdx[0] = keyIndex
   357  			copy(keyIdx[1:], hash)
   358  
   359  			// add delete operation to batch
   360  			s.delete(s.gc.batch.Batch, index, keyIdx, po)
   361  			singleIterationCount++
   362  			s.gc.count++
   363  			log.Trace("garbage collect enqueued chunk for deletion", "key", hash)
   364  
   365  			// break if target is not on max garbage batch boundary
   366  			if s.gc.count >= s.gc.target {
   367  				break
   368  			}
   369  		}
   370  
   371  		s.writeBatch(s.gc.batch, wEntryCnt)
   372  		log.Trace("garbage collect batch done", "batch", singleIterationCount, "total", s.gc.count)
   373  		s.lock.Unlock()
   374  		it.Release()
   375  	}
   376  
   377  	metrics.GetOrRegisterCounter("ldbstore.collectgarbage.delete", nil).Inc(int64(s.gc.count))
   378  	log.Debug("garbage collect done", "c", s.gc.count)
   379  	s.gc.runC <- struct{}{}
   380  
   381  	return nil
   382  }
   383  
   384  // Export writes all chunks from the store to a tar archive, returning the
   385  // number of chunks written.
   386  func (s *LDBStore) Export(out io.Writer) (int64, error) {
   387  	tw := tar.NewWriter(out)
   388  	defer tw.Close()
   389  
   390  	it := s.db.NewIterator()
   391  	defer it.Release()
   392  	var count int64
   393  	for ok := it.Seek([]byte{keyIndex}); ok; ok = it.Next() {
   394  		key := it.Key()
   395  		if (key == nil) || (key[0] != keyIndex) {
   396  			break
   397  		}
   398  
   399  		var index dpaDBIndex
   400  
   401  		hash := key[1:]
   402  		decodeIndex(it.Value(), &index)
   403  		po := s.po(hash)
   404  		datakey := getDataKey(index.Idx, po)
   405  		log.Trace("store.export", "dkey", fmt.Sprintf("%x", datakey), "dataidx", index.Idx, "po", po)
   406  		data, err := s.db.Get(datakey)
   407  		if err != nil {
   408  			log.Warn(fmt.Sprintf("Chunk %x found but could not be accessed: %v", key, err))
   409  			continue
   410  		}
   411  
   412  		hdr := &tar.Header{
   413  			Name: hex.EncodeToString(hash),
   414  			Mode: 0644,
   415  			Size: int64(len(data)),
   416  		}
   417  		if err := tw.WriteHeader(hdr); err != nil {
   418  			return count, err
   419  		}
   420  		if _, err := tw.Write(data); err != nil {
   421  			return count, err
   422  		}
   423  		count++
   424  	}
   425  
   426  	return count, nil
   427  }
   428  
   429  // of chunks read.
   430  func (s *LDBStore) Import(in io.Reader) (int64, error) {
   431  	tr := tar.NewReader(in)
   432  
   433  	ctx, cancel := context.WithCancel(context.Background())
   434  	defer cancel()
   435  
   436  	countC := make(chan int64)
   437  	errC := make(chan error)
   438  	var count int64
   439  	go func() {
   440  		for {
   441  			hdr, err := tr.Next()
   442  			if err == io.EOF {
   443  				break
   444  			} else if err != nil {
   445  				select {
   446  				case errC <- err:
   447  				case <-ctx.Done():
   448  				}
   449  			}
   450  
   451  			if len(hdr.Name) != 64 {
   452  				log.Warn("ignoring non-chunk file", "name", hdr.Name)
   453  				continue
   454  			}
   455  
   456  			keybytes, err := hex.DecodeString(hdr.Name)
   457  			if err != nil {
   458  				log.Warn("ignoring invalid chunk file", "name", hdr.Name, "err", err)
   459  				continue
   460  			}
   461  
   462  			data, err := ioutil.ReadAll(tr)
   463  			if err != nil {
   464  				select {
   465  				case errC <- err:
   466  				case <-ctx.Done():
   467  				}
   468  			}
   469  			key := Address(keybytes)
   470  			chunk := NewChunk(key, data[32:])
   471  
   472  			go func() {
   473  				select {
   474  				case errC <- s.Put(ctx, chunk):
   475  				case <-ctx.Done():
   476  				}
   477  			}()
   478  
   479  			count++
   480  		}
   481  		countC <- count
   482  	}()
   483  
   484  	// wait for all chunks to be stored
   485  	i := int64(0)
   486  	var total int64
   487  	for {
   488  		select {
   489  		case err := <-errC:
   490  			if err != nil {
   491  				return count, err
   492  			}
   493  			i++
   494  		case total = <-countC:
   495  		case <-ctx.Done():
   496  			return i, ctx.Err()
   497  		}
   498  		if total > 0 && i == total {
   499  			return total, nil
   500  		}
   501  	}
   502  }
   503  
   504  // Cleanup iterates over the database and deletes chunks if they pass the `f` condition
   505  func (s *LDBStore) Cleanup(f func(*chunk) bool) {
   506  	var errorsFound, removed, total int
   507  
   508  	it := s.db.NewIterator()
   509  	defer it.Release()
   510  	for ok := it.Seek([]byte{keyIndex}); ok; ok = it.Next() {
   511  		key := it.Key()
   512  		if (key == nil) || (key[0] != keyIndex) {
   513  			break
   514  		}
   515  		total++
   516  		var index dpaDBIndex
   517  		err := decodeIndex(it.Value(), &index)
   518  		if err != nil {
   519  			log.Warn("Cannot decode")
   520  			errorsFound++
   521  			continue
   522  		}
   523  		hash := key[1:]
   524  		po := s.po(hash)
   525  		datakey := getDataKey(index.Idx, po)
   526  		data, err := s.db.Get(datakey)
   527  		if err != nil {
   528  			found := false
   529  
   530  			// highest possible proximity is 255
   531  			for po = 1; po <= 255; po++ {
   532  				datakey = getDataKey(index.Idx, po)
   533  				data, err = s.db.Get(datakey)
   534  				if err == nil {
   535  					found = true
   536  					break
   537  				}
   538  			}
   539  
   540  			if !found {
   541  				log.Warn(fmt.Sprintf("Chunk %x found but count not be accessed with any po", key))
   542  				errorsFound++
   543  				continue
   544  			}
   545  		}
   546  
   547  		ck := data[:32]
   548  		c, err := decodeData(ck, data)
   549  		if err != nil {
   550  			log.Error("decodeData error", "err", err)
   551  			continue
   552  		}
   553  
   554  		cs := int64(binary.LittleEndian.Uint64(c.sdata[:8]))
   555  		log.Trace("chunk", "key", fmt.Sprintf("%x", key), "ck", fmt.Sprintf("%x", ck), "dkey", fmt.Sprintf("%x", datakey), "dataidx", index.Idx, "po", po, "len data", len(data), "len sdata", len(c.sdata), "size", cs)
   556  
   557  		// if chunk is to be removed
   558  		if f(c) {
   559  			log.Warn("chunk for cleanup", "key", fmt.Sprintf("%x", key), "ck", fmt.Sprintf("%x", ck), "dkey", fmt.Sprintf("%x", datakey), "dataidx", index.Idx, "po", po, "len data", len(data), "len sdata", len(c.sdata), "size", cs)
   560  			s.deleteNow(&index, getIndexKey(key[1:]), po)
   561  			removed++
   562  			errorsFound++
   563  		}
   564  	}
   565  
   566  	log.Warn(fmt.Sprintf("Found %v errors out of %v entries. Removed %v chunks.", errorsFound, total, removed))
   567  }
   568  
   569  // CleanGCIndex rebuilds the garbage collector index from scratch, while
   570  // removing inconsistent elements, e.g., indices with missing data chunks.
   571  // WARN: it's a pretty heavy, long running function.
   572  func (s *LDBStore) CleanGCIndex() error {
   573  	s.lock.Lock()
   574  	defer s.lock.Unlock()
   575  
   576  	batch := leveldb.Batch{}
   577  
   578  	var okEntryCount uint64
   579  	var totalEntryCount uint64
   580  
   581  	// throw out all gc indices, we will rebuild from cleaned index
   582  	it := s.db.NewIterator()
   583  	it.Seek([]byte{keyGCIdx})
   584  	var gcDeletes int
   585  	for it.Valid() {
   586  		rowType, _ := parseIdxKey(it.Key())
   587  		if rowType != keyGCIdx {
   588  			break
   589  		}
   590  		batch.Delete(it.Key())
   591  		gcDeletes++
   592  		it.Next()
   593  	}
   594  	log.Debug("gc", "deletes", gcDeletes)
   595  	if err := s.db.Write(&batch); err != nil {
   596  		return err
   597  	}
   598  	batch.Reset()
   599  
   600  	it.Release()
   601  
   602  	// corrected po index pointer values
   603  	var poPtrs [256]uint64
   604  
   605  	// set to true if chunk count not on 4096 iteration boundary
   606  	var doneIterating bool
   607  
   608  	// last key index in previous iteration
   609  	lastIdxKey := []byte{keyIndex}
   610  
   611  	// counter for debug output
   612  	var cleanBatchCount int
   613  
   614  	// go through all key index entries
   615  	for !doneIterating {
   616  		cleanBatchCount++
   617  		var idxs []dpaDBIndex
   618  		var chunkHashes [][]byte
   619  		var pos []uint8
   620  		it := s.db.NewIterator()
   621  
   622  		it.Seek(lastIdxKey)
   623  
   624  		// 4096 is just a nice number, don't look for any hidden meaning here...
   625  		var i int
   626  		for i = 0; i < 4096; i++ {
   627  
   628  			// this really shouldn't happen unless database is empty
   629  			// but let's keep it to be safe
   630  			if !it.Valid() {
   631  				doneIterating = true
   632  				break
   633  			}
   634  
   635  			// if it's not keyindex anymore we're done iterating
   636  			rowType, chunkHash := parseIdxKey(it.Key())
   637  			if rowType != keyIndex {
   638  				doneIterating = true
   639  				break
   640  			}
   641  
   642  			// decode the retrieved index
   643  			var idx dpaDBIndex
   644  			err := decodeIndex(it.Value(), &idx)
   645  			if err != nil {
   646  				return fmt.Errorf("corrupt index: %v", err)
   647  			}
   648  			po := s.po(chunkHash)
   649  			lastIdxKey = it.Key()
   650  
   651  			// if we don't find the data key, remove the entry
   652  			// if we find it, add to the array of new gc indices to create
   653  			dataKey := getDataKey(idx.Idx, po)
   654  			_, err = s.db.Get(dataKey)
   655  			if err != nil {
   656  				log.Warn("deleting inconsistent index (missing data)", "key", chunkHash)
   657  				batch.Delete(it.Key())
   658  			} else {
   659  				idxs = append(idxs, idx)
   660  				chunkHashes = append(chunkHashes, chunkHash)
   661  				pos = append(pos, po)
   662  				okEntryCount++
   663  				if idx.Idx > poPtrs[po] {
   664  					poPtrs[po] = idx.Idx
   665  				}
   666  			}
   667  			totalEntryCount++
   668  			it.Next()
   669  		}
   670  		it.Release()
   671  
   672  		// flush the key index corrections
   673  		err := s.db.Write(&batch)
   674  		if err != nil {
   675  			return err
   676  		}
   677  		batch.Reset()
   678  
   679  		// add correct gc indices
   680  		for i, okIdx := range idxs {
   681  			gcIdxKey := getGCIdxKey(&okIdx)
   682  			gcIdxData := getGCIdxValue(&okIdx, pos[i], chunkHashes[i])
   683  			batch.Put(gcIdxKey, gcIdxData)
   684  			log.Trace("clean ok", "key", chunkHashes[i], "gcKey", gcIdxKey, "gcData", gcIdxData)
   685  		}
   686  
   687  		// flush them
   688  		err = s.db.Write(&batch)
   689  		if err != nil {
   690  			return err
   691  		}
   692  		batch.Reset()
   693  
   694  		log.Debug("clean gc index pass", "batch", cleanBatchCount, "checked", i, "kept", len(idxs))
   695  	}
   696  
   697  	log.Debug("gc cleanup entries", "ok", okEntryCount, "total", totalEntryCount, "batchlen", batch.Len())
   698  
   699  	// lastly add updated entry count
   700  	var entryCount [8]byte
   701  	binary.BigEndian.PutUint64(entryCount[:], okEntryCount)
   702  	batch.Put(keyEntryCnt, entryCount[:])
   703  
   704  	// and add the new po index pointers
   705  	var poKey [2]byte
   706  	poKey[0] = keyDistanceCnt
   707  	for i, poPtr := range poPtrs {
   708  		poKey[1] = uint8(i)
   709  		if poPtr == 0 {
   710  			batch.Delete(poKey[:])
   711  		} else {
   712  			var idxCount [8]byte
   713  			binary.BigEndian.PutUint64(idxCount[:], poPtr)
   714  			batch.Put(poKey[:], idxCount[:])
   715  		}
   716  	}
   717  
   718  	// if you made it this far your harddisk has survived. Congratulations
   719  	return s.db.Write(&batch)
   720  }
   721  
   722  // Delete is removes a chunk and updates indices.
   723  // Is thread safe
   724  func (s *LDBStore) Delete(addr Address) error {
   725  	s.lock.Lock()
   726  	defer s.lock.Unlock()
   727  
   728  	ikey := getIndexKey(addr)
   729  
   730  	idata, err := s.db.Get(ikey)
   731  	if err != nil {
   732  		return err
   733  	}
   734  
   735  	var idx dpaDBIndex
   736  	decodeIndex(idata, &idx)
   737  	proximity := s.po(addr)
   738  	return s.deleteNow(&idx, ikey, proximity)
   739  }
   740  
   741  // executes one delete operation immediately
   742  // see *LDBStore.delete
   743  func (s *LDBStore) deleteNow(idx *dpaDBIndex, idxKey []byte, po uint8) error {
   744  	batch := new(leveldb.Batch)
   745  	s.delete(batch, idx, idxKey, po)
   746  	return s.db.Write(batch)
   747  }
   748  
   749  // adds a delete chunk operation to the provided batch
   750  // if called directly, decrements entrycount regardless if the chunk exists upon deletion. Risk of wrap to max uint64
   751  func (s *LDBStore) delete(batch *leveldb.Batch, idx *dpaDBIndex, idxKey []byte, po uint8) {
   752  	metrics.GetOrRegisterCounter("ldbstore.delete", nil).Inc(1)
   753  
   754  	gcIdxKey := getGCIdxKey(idx)
   755  	batch.Delete(gcIdxKey)
   756  	dataKey := getDataKey(idx.Idx, po)
   757  	batch.Delete(dataKey)
   758  	batch.Delete(idxKey)
   759  	s.entryCnt--
   760  	dbEntryCount.Dec(1)
   761  	cntKey := make([]byte, 2)
   762  	cntKey[0] = keyDistanceCnt
   763  	cntKey[1] = po
   764  	batch.Put(keyEntryCnt, U64ToBytes(s.entryCnt))
   765  	batch.Put(cntKey, U64ToBytes(s.bucketCnt[po]))
   766  }
   767  
   768  func (s *LDBStore) BinIndex(po uint8) uint64 {
   769  	s.lock.RLock()
   770  	defer s.lock.RUnlock()
   771  	return s.bucketCnt[po]
   772  }
   773  
   774  // Put adds a chunk to the database, adding indices and incrementing global counters.
   775  // If it already exists, it merely increments the access count of the existing entry.
   776  // Is thread safe
   777  func (s *LDBStore) Put(ctx context.Context, chunk Chunk) error {
   778  	metrics.GetOrRegisterCounter("ldbstore.put", nil).Inc(1)
   779  	log.Trace("ldbstore.put", "key", chunk.Address())
   780  
   781  	ikey := getIndexKey(chunk.Address())
   782  	var index dpaDBIndex
   783  
   784  	po := s.po(chunk.Address())
   785  
   786  	s.lock.Lock()
   787  
   788  	if s.closed {
   789  		s.lock.Unlock()
   790  		return ErrDBClosed
   791  	}
   792  	batch := s.batch
   793  
   794  	log.Trace("ldbstore.put: s.db.Get", "key", chunk.Address(), "ikey", fmt.Sprintf("%x", ikey))
   795  	_, err := s.db.Get(ikey)
   796  	if err != nil {
   797  		s.doPut(chunk, &index, po)
   798  	}
   799  	idata := encodeIndex(&index)
   800  	s.batch.Put(ikey, idata)
   801  
   802  	// add the access-chunkindex index for garbage collection
   803  	gcIdxKey := getGCIdxKey(&index)
   804  	gcIdxData := getGCIdxValue(&index, po, chunk.Address())
   805  	s.batch.Put(gcIdxKey, gcIdxData)
   806  	s.lock.Unlock()
   807  
   808  	select {
   809  	case s.batchesC <- struct{}{}:
   810  	default:
   811  	}
   812  
   813  	select {
   814  	case <-batch.c:
   815  		return batch.err
   816  	case <-ctx.Done():
   817  		return ctx.Err()
   818  	}
   819  }
   820  
   821  // force putting into db, does not check or update necessary indices
   822  func (s *LDBStore) doPut(chunk Chunk, index *dpaDBIndex, po uint8) {
   823  	data := s.encodeDataFunc(chunk)
   824  	dkey := getDataKey(s.dataIdx, po)
   825  	s.batch.Put(dkey, data)
   826  	index.Idx = s.dataIdx
   827  	s.bucketCnt[po] = s.dataIdx
   828  	s.entryCnt++
   829  	dbEntryCount.Inc(1)
   830  	s.dataIdx++
   831  	index.Access = s.accessCnt
   832  	s.accessCnt++
   833  	cntKey := make([]byte, 2)
   834  	cntKey[0] = keyDistanceCnt
   835  	cntKey[1] = po
   836  	s.batch.Put(cntKey, U64ToBytes(s.bucketCnt[po]))
   837  }
   838  
   839  func (s *LDBStore) writeBatches() {
   840  	for {
   841  		select {
   842  		case <-s.quit:
   843  			log.Debug("DbStore: quit batch write loop")
   844  			return
   845  		case <-s.batchesC:
   846  			err := s.writeCurrentBatch()
   847  			if err != nil {
   848  				log.Debug("DbStore: quit batch write loop", "err", err.Error())
   849  				return
   850  			}
   851  		}
   852  	}
   853  
   854  }
   855  
   856  func (s *LDBStore) writeCurrentBatch() error {
   857  	s.lock.Lock()
   858  	defer s.lock.Unlock()
   859  	b := s.batch
   860  	l := b.Len()
   861  	if l == 0 {
   862  		return nil
   863  	}
   864  	s.batch = newBatch()
   865  	b.err = s.writeBatch(b, wEntryCnt|wAccessCnt|wIndexCnt)
   866  	close(b.c)
   867  	if s.entryCnt >= s.capacity {
   868  		go s.collectGarbage()
   869  	}
   870  	return nil
   871  }
   872  
   873  // must be called non concurrently
   874  func (s *LDBStore) writeBatch(b *dbBatch, wFlag uint8) error {
   875  	if wFlag&wEntryCnt > 0 {
   876  		b.Put(keyEntryCnt, U64ToBytes(s.entryCnt))
   877  	}
   878  	if wFlag&wIndexCnt > 0 {
   879  		b.Put(keyDataIdx, U64ToBytes(s.dataIdx))
   880  	}
   881  	if wFlag&wAccessCnt > 0 {
   882  		b.Put(keyAccessCnt, U64ToBytes(s.accessCnt))
   883  	}
   884  	l := b.Len()
   885  	if err := s.db.Write(b.Batch); err != nil {
   886  		return fmt.Errorf("unable to write batch: %v", err)
   887  	}
   888  	log.Trace(fmt.Sprintf("batch write (%d entries)", l))
   889  	return nil
   890  }
   891  
   892  // newMockEncodeDataFunc returns a function that stores the chunk data
   893  // to a mock store to bypass the default functionality encodeData.
   894  // The constructed function always returns the nil data, as DbStore does
   895  // not need to store the data, but still need to create the index.
   896  func newMockEncodeDataFunc(mockStore *mock.NodeStore) func(chunk Chunk) []byte {
   897  	return func(chunk Chunk) []byte {
   898  		if err := mockStore.Put(chunk.Address(), encodeData(chunk)); err != nil {
   899  			log.Error(fmt.Sprintf("%T: Chunk %v put: %v", mockStore, chunk.Address().Log(), err))
   900  		}
   901  		return chunk.Address()[:]
   902  	}
   903  }
   904  
   905  // tryAccessIdx tries to find index entry. If found then increments the access
   906  // count for garbage collection and returns the index entry and true for found,
   907  // otherwise returns nil and false.
   908  func (s *LDBStore) tryAccessIdx(addr Address, po uint8) (*dpaDBIndex, bool) {
   909  	ikey := getIndexKey(addr)
   910  	idata, err := s.db.Get(ikey)
   911  	if err != nil {
   912  		return nil, false
   913  	}
   914  
   915  	index := new(dpaDBIndex)
   916  	decodeIndex(idata, index)
   917  	oldGCIdxKey := getGCIdxKey(index)
   918  	s.batch.Put(keyAccessCnt, U64ToBytes(s.accessCnt))
   919  	index.Access = s.accessCnt
   920  	idata = encodeIndex(index)
   921  	s.accessCnt++
   922  	s.batch.Put(ikey, idata)
   923  	newGCIdxKey := getGCIdxKey(index)
   924  	newGCIdxData := getGCIdxValue(index, po, ikey[1:])
   925  	s.batch.Delete(oldGCIdxKey)
   926  	s.batch.Put(newGCIdxKey, newGCIdxData)
   927  	select {
   928  	case s.batchesC <- struct{}{}:
   929  	default:
   930  	}
   931  	return index, true
   932  }
   933  
   934  // GetSchema is returning the current named schema of the datastore as read from LevelDB
   935  func (s *LDBStore) GetSchema() (string, error) {
   936  	s.lock.Lock()
   937  	defer s.lock.Unlock()
   938  
   939  	data, err := s.db.Get(keySchema)
   940  	if err != nil {
   941  		if err == leveldb.ErrNotFound {
   942  			return DbSchemaNone, nil
   943  		}
   944  		return "", err
   945  	}
   946  
   947  	return string(data), nil
   948  }
   949  
   950  // PutSchema is saving a named schema to the LevelDB datastore
   951  func (s *LDBStore) PutSchema(schema string) error {
   952  	s.lock.Lock()
   953  	defer s.lock.Unlock()
   954  
   955  	return s.db.Put(keySchema, []byte(schema))
   956  }
   957  
   958  // Get retrieves the chunk matching the provided key from the database.
   959  // If the chunk entry does not exist, it returns an error
   960  // Updates access count and is thread safe
   961  func (s *LDBStore) Get(_ context.Context, addr Address) (chunk Chunk, err error) {
   962  	metrics.GetOrRegisterCounter("ldbstore.get", nil).Inc(1)
   963  	log.Trace("ldbstore.get", "key", addr)
   964  
   965  	s.lock.Lock()
   966  	defer s.lock.Unlock()
   967  	return s.get(addr)
   968  }
   969  
   970  // Has queries the underlying DB if a chunk with the given address is stored
   971  // Returns true if the chunk is found, false if not
   972  func (s *LDBStore) Has(_ context.Context, addr Address) bool {
   973  	s.lock.RLock()
   974  	defer s.lock.RUnlock()
   975  
   976  	ikey := getIndexKey(addr)
   977  	_, err := s.db.Get(ikey)
   978  
   979  	return err == nil
   980  }
   981  
   982  // TODO: To conform with other private methods of this object indices should not be updated
   983  func (s *LDBStore) get(addr Address) (chunk *chunk, err error) {
   984  	if s.closed {
   985  		return nil, ErrDBClosed
   986  	}
   987  	proximity := s.po(addr)
   988  	index, found := s.tryAccessIdx(addr, proximity)
   989  	if found {
   990  		var data []byte
   991  		if s.getDataFunc != nil {
   992  			// if getDataFunc is defined, use it to retrieve the chunk data
   993  			log.Trace("ldbstore.get retrieve with getDataFunc", "key", addr)
   994  			data, err = s.getDataFunc(addr)
   995  			if err != nil {
   996  				return
   997  			}
   998  		} else {
   999  			// default DbStore functionality to retrieve chunk data
  1000  			datakey := getDataKey(index.Idx, proximity)
  1001  			data, err = s.db.Get(datakey)
  1002  			log.Trace("ldbstore.get retrieve", "key", addr, "indexkey", index.Idx, "datakey", fmt.Sprintf("%x", datakey), "proximity", proximity)
  1003  			if err != nil {
  1004  				log.Trace("ldbstore.get chunk found but could not be accessed", "key", addr, "err", err)
  1005  				s.deleteNow(index, getIndexKey(addr), s.po(addr))
  1006  				return
  1007  			}
  1008  		}
  1009  
  1010  		return decodeData(addr, data)
  1011  	} else {
  1012  		err = ErrChunkNotFound
  1013  	}
  1014  
  1015  	return
  1016  }
  1017  
  1018  // newMockGetFunc returns a function that reads chunk data from
  1019  // the mock database, which is used as the value for DbStore.getFunc
  1020  // to bypass the default functionality of DbStore with a mock store.
  1021  func newMockGetDataFunc(mockStore *mock.NodeStore) func(addr Address) (data []byte, err error) {
  1022  	return func(addr Address) (data []byte, err error) {
  1023  		data, err = mockStore.Get(addr)
  1024  		if err == mock.ErrNotFound {
  1025  			// preserve ErrChunkNotFound error
  1026  			err = ErrChunkNotFound
  1027  		}
  1028  		return data, err
  1029  	}
  1030  }
  1031  
  1032  func (s *LDBStore) setCapacity(c uint64) {
  1033  	s.lock.Lock()
  1034  	defer s.lock.Unlock()
  1035  
  1036  	s.capacity = c
  1037  
  1038  	for s.entryCnt > c {
  1039  		s.collectGarbage()
  1040  	}
  1041  }
  1042  
  1043  func (s *LDBStore) Close() {
  1044  	close(s.quit)
  1045  	s.lock.Lock()
  1046  	s.closed = true
  1047  	s.lock.Unlock()
  1048  	// force writing out current batch
  1049  	s.writeCurrentBatch()
  1050  	s.db.Close()
  1051  }
  1052  
  1053  // SyncIterator(start, stop, po, f) calls f on each hash of a bin po from start to stop
  1054  func (s *LDBStore) SyncIterator(since uint64, until uint64, po uint8, f func(Address, uint64) bool) error {
  1055  	metrics.GetOrRegisterCounter("ldbstore.synciterator", nil).Inc(1)
  1056  
  1057  	sincekey := getDataKey(since, po)
  1058  	untilkey := getDataKey(until, po)
  1059  	it := s.db.NewIterator()
  1060  	defer it.Release()
  1061  
  1062  	for ok := it.Seek(sincekey); ok; ok = it.Next() {
  1063  		metrics.GetOrRegisterCounter("ldbstore.synciterator.seek", nil).Inc(1)
  1064  
  1065  		dbkey := it.Key()
  1066  		if dbkey[0] != keyData || dbkey[1] != po || bytes.Compare(untilkey, dbkey) < 0 {
  1067  			break
  1068  		}
  1069  		key := make([]byte, 32)
  1070  		val := it.Value()
  1071  		copy(key, val[:32])
  1072  		if !f(Address(key), binary.BigEndian.Uint64(dbkey[2:])) {
  1073  			break
  1074  		}
  1075  	}
  1076  	return it.Error()
  1077  }