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() {}