github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/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 return len(m.data) == 0 38 } 39 40 // pickKey randomly selects a key that already exists in a given copy of the 41 // map's contents. Assumes that the copy is non-empty. 42 func (m *mapContents) pickKey(prng *rand.Rand) []byte { 43 if m.empty() { 44 panic("internal error: can't pick a key, map data is empty!") 45 } 46 47 choice := prng.Intn(len(m.data)) 48 // Need sorted keys for reproduceability. 49 keys := make([]mapKey, 0) 50 for k := range m.data { 51 keys = append(keys, k) 52 } 53 sort.SliceStable(keys, func(i, j int) bool { 54 return bytes.Compare(keys[i][:], keys[j][:]) == -1 55 }) 56 return keys[choice][:] 57 } 58 59 // checkContents compares information returned from the Map against a local copy 60 // of the map's contents. 61 func (m *mapContents) checkContents(leafInclusions []*trillian.MapLeafInclusion, extraSize uint) error { 62 for _, inc := range leafInclusions { 63 leaf := inc.Leaf 64 var key mapKey 65 copy(key[:], leaf.Index) 66 value, ok := m.data[key] 67 if ok { 68 if string(leaf.LeafValue) != value { 69 return fmt.Errorf("got leaf[%v].LeafValue=%q, want %q", key, leaf.LeafValue, value) 70 } 71 if want := extraDataForValue(leaf.LeafValue, extraSize); !bytes.Equal(leaf.ExtraData, want) { 72 return fmt.Errorf("got leaf[%v].ExtraData=%q, want %q", key, leaf.ExtraData, want) 73 } 74 } else { 75 if len(leaf.LeafValue) > 0 { 76 return fmt.Errorf("got leaf[%v].LeafValue=%q, want not-present", key, leaf.LeafValue) 77 } 78 } 79 } 80 return nil 81 } 82 83 // updatedWith returns a new mapContents object that has been updated to include the 84 // given leaves and revision. A nil receiver object is allowed. 85 func (m *mapContents) updatedWith(rev uint64, leaves []*trillian.MapLeaf) *mapContents { 86 // Start from previous map contents 87 result := mapContents{rev: int64(rev), data: make(map[mapKey]string)} 88 if m != nil { 89 for k, v := range m.data { 90 result.data[k] = v 91 } 92 } 93 // Update with given leaves 94 for _, leaf := range leaves { 95 var k mapKey 96 copy(k[:], leaf.Index) 97 if leaf.LeafValue != nil { 98 result.data[k] = string(leaf.LeafValue) 99 } else { 100 delete(result.data, k) 101 } 102 } 103 104 return &result 105 } 106 107 // How many copies of map contents to hold on to. 108 const copyCount = 10 109 110 type versionedMapContents struct { 111 mu sync.RWMutex 112 113 // contents holds copies of the map at different revisions, 114 // from later to earlier (so [0] is the most recent). 115 contents [copyCount]*mapContents 116 } 117 118 func (p *versionedMapContents) empty() bool { 119 return p.lastCopy() == nil 120 } 121 122 // prevCopy returns the specified copy of the map's contents. 123 func (p *versionedMapContents) prevCopy(which int) *mapContents { 124 p.mu.RLock() 125 defer p.mu.RUnlock() 126 return p.contents[which] 127 } 128 129 // lastCopy returns the most recent copy of the map's contents. 130 func (p *versionedMapContents) lastCopy() *mapContents { 131 return p.prevCopy(0) 132 } 133 134 // pickCopy returns a previous copy of the map's contents, returning 135 // nil if there are no local copies. 136 func (p *versionedMapContents) pickCopy(prng *rand.Rand) *mapContents { 137 p.mu.RLock() 138 defer p.mu.RUnlock() 139 // Count the number of filled copies. 140 i := 0 141 for ; i < copyCount; i++ { 142 if p.contents[i] == nil { 143 break 144 } 145 } 146 if i == 0 { 147 // No copied contents yet 148 return nil 149 } 150 choice := prng.Intn(i) 151 return p.contents[choice] 152 } 153 154 func (p *versionedMapContents) updateContentsWith(rev uint64, leaves []*trillian.MapLeaf) error { 155 p.mu.Lock() 156 defer p.mu.Unlock() 157 158 // Sanity check on rev being +ve and monotone increasing. 159 if rev < 1 { 160 return errInvariant{fmt.Sprintf("got rev %d, want >=1 when trying to update hammer state with contents", rev)} 161 } 162 if p.contents[0] != nil && int64(rev) <= p.contents[0].rev { 163 return errInvariant{fmt.Sprintf("got rev %d, want >%d when trying to update hammer state with new contents", rev, p.contents[0].rev)} 164 } 165 166 // Shuffle earlier contents along. 167 for i := copyCount - 1; i > 0; i-- { 168 p.contents[i] = p.contents[i-1] 169 } 170 p.contents[0] = p.contents[1].updatedWith(rev, leaves) 171 172 if glog.V(3) { 173 p.dumpLockedContents() 174 } 175 return nil 176 } 177 178 // dumpLockedContents shows the local copies of the map's contents; it should be called with p.mu held. 179 func (p *versionedMapContents) dumpLockedContents() { 180 fmt.Println("Contents\n~~~~~~~~") 181 for i, c := range p.contents { 182 if c == nil { 183 break 184 } 185 fmt.Printf(" slot #%d\n", i) 186 fmt.Printf(" revision: %d\n", c.rev) 187 fmt.Println(" data:") 188 for k, v := range c.data { 189 fmt.Printf(" k: %s v: %v\n", string(k[:]), v) 190 } 191 } 192 fmt.Println("~~~~~~~~") 193 }