github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/shed/field_uint64.go (about) 1 // Copyleft 2018 The susy-graviton Authors 2 // This file is part of the susy-graviton library. 3 // 4 // The susy-graviton 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 susy-graviton library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MSRCHANTABILITY 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 susy-graviton library. If not, see <http://www.gnu.org/licenses/>. 16 17 package shed 18 19 import ( 20 "encoding/binary" 21 22 "github.com/syndtr/goleveldb/leveldb" 23 ) 24 25 // Uint64Field provides a way to have a simple counter in the database. 26 // It transparently encodes uint64 type value to bytes. 27 type Uint64Field struct { 28 db *DB 29 key []byte 30 } 31 32 // NewUint64Field returns a new Uint64Field. 33 // It validates its name and type against the database schema. 34 func (db *DB) NewUint64Field(name string) (f Uint64Field, err error) { 35 key, err := db.schemaFieldKey(name, "uint64") 36 if err != nil { 37 return f, err 38 } 39 return Uint64Field{ 40 db: db, 41 key: key, 42 }, nil 43 } 44 45 // Get retrieves a uint64 value from the database. 46 // If the value is not found in the database a 0 value 47 // is returned and no error. 48 func (f Uint64Field) Get() (val uint64, err error) { 49 b, err := f.db.Get(f.key) 50 if err != nil { 51 if err == leveldb.ErrNotFound { 52 return 0, nil 53 } 54 return 0, err 55 } 56 return binary.BigEndian.Uint64(b), nil 57 } 58 59 // Put encodes uin64 value and stores it in the database. 60 func (f Uint64Field) Put(val uint64) (err error) { 61 return f.db.Put(f.key, encodeUint64(val)) 62 } 63 64 // PutInBatch stores a uint64 value in a batch 65 // that can be saved later in the database. 66 func (f Uint64Field) PutInBatch(batch *leveldb.Batch, val uint64) { 67 batch.Put(f.key, encodeUint64(val)) 68 } 69 70 // Inc increments a uint64 value in the database. 71 // This operation is not goroutine save. 72 func (f Uint64Field) Inc() (val uint64, err error) { 73 val, err = f.Get() 74 if err != nil { 75 if err == leveldb.ErrNotFound { 76 val = 0 77 } else { 78 return 0, err 79 } 80 } 81 val++ 82 return val, f.Put(val) 83 } 84 85 // IncInBatch increments a uint64 value in the batch 86 // by retreiving a value from the database, not the same batch. 87 // This operation is not goroutine save. 88 func (f Uint64Field) IncInBatch(batch *leveldb.Batch) (val uint64, err error) { 89 val, err = f.Get() 90 if err != nil { 91 if err == leveldb.ErrNotFound { 92 val = 0 93 } else { 94 return 0, err 95 } 96 } 97 val++ 98 f.PutInBatch(batch, val) 99 return val, nil 100 } 101 102 // Dec decrements a uint64 value in the database. 103 // This operation is not goroutine save. 104 // The field is protected from overflow to a negative value. 105 func (f Uint64Field) Dec() (val uint64, err error) { 106 val, err = f.Get() 107 if err != nil { 108 if err == leveldb.ErrNotFound { 109 val = 0 110 } else { 111 return 0, err 112 } 113 } 114 if val != 0 { 115 val-- 116 } 117 return val, f.Put(val) 118 } 119 120 // DecInBatch decrements a uint64 value in the batch 121 // by retreiving a value from the database, not the same batch. 122 // This operation is not goroutine save. 123 // The field is protected from overflow to a negative value. 124 func (f Uint64Field) DecInBatch(batch *leveldb.Batch) (val uint64, err error) { 125 val, err = f.Get() 126 if err != nil { 127 if err == leveldb.ErrNotFound { 128 val = 0 129 } else { 130 return 0, err 131 } 132 } 133 if val != 0 { 134 val-- 135 } 136 f.PutInBatch(batch, val) 137 return val, nil 138 } 139 140 // encode transforms uint64 to 8 byte long 141 // slice in big endian encoding. 142 func encodeUint64(val uint64) (b []byte) { 143 b = make([]byte, 8) 144 binary.BigEndian.PutUint64(b, val) 145 return b 146 }