github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/merkle/file_hash_store.go (about)

     1  /*
     2   * Copyright (C) 2018 The ontology Authors
     3   * This file is part of The ontology library.
     4   *
     5   * The ontology is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU Lesser 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 ontology 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 Lesser General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU Lesser General Public License
    16   * along with The ontology.  If not, see <http://www.gnu.org/licenses/>.
    17   */
    18  
    19  package merkle
    20  
    21  import (
    22  	"errors"
    23  	"io"
    24  	"os"
    25  
    26  	"github.com/sixexorg/magnetic-ring/common"
    27  )
    28  
    29  // HashStore is an interface for persist hash
    30  type HashStore interface {
    31  	Append(hash []common.Hash) error
    32  	//Truncate(pos uint64) error
    33  	Flush() error
    34  	Close()
    35  	GetHash(pos uint64) (common.Hash, error)
    36  }
    37  
    38  type fileHashStore struct {
    39  	file_name string
    40  	file      *os.File
    41  }
    42  
    43  // NewFileHashStore returns a HashStore implement in file
    44  func NewFileHashStore(name string, tree_size uint64) (HashStore, error) {
    45  	f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, 0755)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	store := &fileHashStore{
    50  		file_name: name,
    51  		file:      f,
    52  	}
    53  
    54  	err = store.checkConsistence(tree_size)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	num_hashes := getStoredHashNum(tree_size)
    60  	size := int64(num_hashes) * int64(common.HashLength)
    61  	_, err = store.file.Seek(size, io.SeekStart)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	return store, nil
    66  }
    67  
    68  func getStoredHashNum(tree_size uint64) int64 {
    69  	subtreesize := getSubTreeSize(tree_size)
    70  	sum := int64(0)
    71  	for _, v := range subtreesize {
    72  		sum += int64(v)
    73  	}
    74  
    75  	return sum
    76  }
    77  
    78  func (self *fileHashStore) checkConsistence(tree_size uint64) error {
    79  	num_hashes := getStoredHashNum(tree_size)
    80  
    81  	stat, err := self.file.Stat()
    82  	if err != nil {
    83  		return err
    84  	} else if stat.Size() < int64(num_hashes)*int64(common.HashLength) {
    85  		return errors.New("stored hashes are less than expected")
    86  	}
    87  	return nil
    88  }
    89  
    90  func (self *fileHashStore) Append(hash []common.Hash) error {
    91  	if self == nil {
    92  		return nil
    93  	}
    94  	buf := make([]byte, 0, len(hash)*common.HashLength)
    95  	for _, h := range hash {
    96  		buf = append(buf, h[:]...)
    97  	}
    98  	_, err := self.file.Write(buf)
    99  	return err
   100  }
   101  func (self *fileHashStore) Truncate(pos uint64) error {
   102  	if self == nil {
   103  		return nil
   104  	}
   105  	err := self.file.Truncate(int64(pos))
   106  	return err
   107  }
   108  
   109  func (self *fileHashStore) Flush() error {
   110  	if self == nil {
   111  		return nil
   112  	}
   113  	return self.file.Sync()
   114  }
   115  
   116  func (self *fileHashStore) Close() {
   117  	if self == nil {
   118  		return
   119  	}
   120  	self.file.Close()
   121  }
   122  
   123  func (self *fileHashStore) GetHash(pos uint64) (common.Hash, error) {
   124  	if self == nil {
   125  		return common.Hash{}, errors.New("FileHashstore is nil")
   126  	}
   127  	hash := common.Hash{}
   128  	_, err := self.file.ReadAt(hash[:], int64(pos)*int64(common.HashLength))
   129  	if err != nil {
   130  		return common.Hash{}, err
   131  	}
   132  
   133  	return hash, nil
   134  }
   135  
   136  type memHashStore struct {
   137  	hashes []common.Hash
   138  }
   139  
   140  // NewMemHashStore returns a HashStore implement in memory
   141  func NewMemHashStore() HashStore {
   142  	return &memHashStore{}
   143  }
   144  
   145  func (self *memHashStore) Append(hash []common.Hash) error {
   146  	self.hashes = append(self.hashes, hash...)
   147  	return nil
   148  }
   149  
   150  func (self *memHashStore) GetHash(pos uint64) (common.Hash, error) {
   151  	return self.hashes[pos], nil
   152  }
   153  
   154  func (self *memHashStore) Flush() error {
   155  	return nil
   156  }
   157  
   158  func (self *memHashStore) Close() {}