github.com/bartle-stripe/trillian@v1.2.1/testonly/hammer/contents.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package hammer 16 17 import ( 18 "bytes" 19 "crypto/sha256" 20 "fmt" 21 "math/rand" 22 "sort" 23 "sync" 24 25 "github.com/golang/glog" 26 "github.com/google/trillian" 27 ) 28 29 // mapContents is a complete copy of the map's contents at a particular revision. 30 type mapContents struct { 31 data map[mapKey]string 32 rev int64 33 } 34 type mapKey [sha256.Size]byte 35 36 func (m *mapContents) empty() bool { 37 if m == nil { 38 return true 39 } 40 return len(m.data) == 0 41 } 42 43 // pickKey randomly selects a key that already exists in a given copy of the 44 // map's contents. Assumes that the copy is non-empty. 45 func (m *mapContents) pickKey(prng *rand.Rand) []byte { 46 if m.empty() { 47 panic("internal error: can't pick a key, map data is empty!") 48 } 49 50 choice := prng.Intn(len(m.data)) 51 // Need sorted keys for reproduceability. 52 keys := make([]mapKey, 0) 53 for k := range m.data { 54 keys = append(keys, k) 55 } 56 sort.SliceStable(keys, func(i, j int) bool { 57 return bytes.Compare(keys[i][:], keys[j][:]) == -1 58 }) 59 return keys[choice][:] 60 } 61 62 // checkContents compares information returned from the Map against a local copy 63 // of the map's contents. 64 func (m *mapContents) checkContents(leafInclusions []*trillian.MapLeafInclusion, extraSize uint) error { 65 for _, inc := range leafInclusions { 66 leaf := inc.Leaf 67 var key mapKey 68 copy(key[:], leaf.Index) 69 value, ok := m.data[key] 70 if ok { 71 if string(leaf.LeafValue) != value { 72 return fmt.Errorf("got leaf[%v].LeafValue=%q, want %q", key, leaf.LeafValue, value) 73 } 74 if want := extraDataForValue(leaf.LeafValue, extraSize); !bytes.Equal(leaf.ExtraData, want) { 75 return fmt.Errorf("got leaf[%v].ExtraData=%q, want %q", key, leaf.ExtraData, want) 76 } 77 } else { 78 if len(leaf.LeafValue) > 0 { 79 return fmt.Errorf("got leaf[%v].LeafValue=%q, want not-present", key, leaf.LeafValue) 80 } 81 } 82 } 83 return nil 84 } 85 86 // updatedWith returns a new mapContents object that has been updated to include the 87 // given leaves and revision. A nil receiver object is allowed. 88 func (m *mapContents) updatedWith(rev uint64, leaves []*trillian.MapLeaf) *mapContents { 89 // Start from previous map contents 90 result := mapContents{rev: int64(rev), data: make(map[mapKey]string)} 91 if m != nil { 92 for k, v := range m.data { 93 result.data[k] = v 94 } 95 } 96 // Update with given leaves 97 for _, leaf := range leaves { 98 var k mapKey 99 copy(k[:], leaf.Index) 100 if leaf.LeafValue != nil { 101 result.data[k] = string(leaf.LeafValue) 102 } else { 103 delete(result.data, k) 104 } 105 } 106 107 return &result 108 } 109 110 // How many copies of map contents to hold on to. 111 const copyCount = 10 112 113 type versionedMapContents struct { 114 mu sync.RWMutex 115 116 // contents holds copies of the map at different revisions, 117 // from later to earlier (so [0] is the most recent). 118 contents [copyCount]*mapContents 119 } 120 121 func (p *versionedMapContents) empty() bool { 122 return p.lastCopy() == nil 123 } 124 125 // prevCopy returns the specified copy of the map's contents. 126 func (p *versionedMapContents) prevCopy(which int) *mapContents { 127 p.mu.RLock() 128 defer p.mu.RUnlock() 129 return p.contents[which] 130 } 131 132 // lastCopy returns the most recent copy of the map's contents. 133 func (p *versionedMapContents) lastCopy() *mapContents { 134 return p.prevCopy(0) 135 } 136 137 // pickCopy returns a previous copy of the map's contents, returning 138 // nil if there are no local copies. 139 func (p *versionedMapContents) pickCopy(prng *rand.Rand) *mapContents { 140 p.mu.RLock() 141 defer p.mu.RUnlock() 142 // Count the number of filled copies. 143 i := 0 144 for ; i < copyCount; i++ { 145 if p.contents[i] == nil { 146 break 147 } 148 } 149 if i == 0 { 150 // No copied contents yet 151 return nil 152 } 153 choice := prng.Intn(i) 154 return p.contents[choice] 155 } 156 157 func (p *versionedMapContents) updateContentsWith(rev uint64, leaves []*trillian.MapLeaf) error { 158 p.mu.Lock() 159 defer p.mu.Unlock() 160 161 // Sanity check on rev being +ve and monotone increasing. 162 if rev < 1 { 163 return errInvariant{fmt.Sprintf("got rev %d, want >=1 when trying to update hammer state with contents", rev)} 164 } 165 if p.contents[0] != nil && int64(rev) <= p.contents[0].rev { 166 return errInvariant{fmt.Sprintf("got rev %d, want >%d when trying to update hammer state with new contents", rev, p.contents[0].rev)} 167 } 168 169 // Shuffle earlier contents along. 170 for i := copyCount - 1; i > 0; i-- { 171 p.contents[i] = p.contents[i-1] 172 } 173 p.contents[0] = p.contents[1].updatedWith(rev, leaves) 174 175 if glog.V(3) { 176 p.dumpLockedContents() 177 } 178 return nil 179 } 180 181 // dumpLockedContents shows the local copies of the map's contents; it should be called with p.mu held. 182 func (p *versionedMapContents) dumpLockedContents() { 183 fmt.Println("Contents\n~~~~~~~~") 184 for i, c := range p.contents { 185 if c == nil { 186 break 187 } 188 fmt.Printf(" slot #%d\n", i) 189 fmt.Printf(" revision: %d\n", c.rev) 190 fmt.Println(" data:") 191 for k, v := range c.data { 192 fmt.Printf(" k: %s v: %v\n", string(k[:]), v) 193 } 194 } 195 fmt.Println("~~~~~~~~") 196 }