github.com/m3db/m3@v1.5.0/src/dbnode/storage/block/result.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package block 22 23 import ( 24 "sort" 25 26 "github.com/m3db/m3/src/dbnode/x/xio" 27 "github.com/m3db/m3/src/x/ident" 28 xtime "github.com/m3db/m3/src/x/time" 29 ) 30 31 // NewFetchBlockResult creates a new fetch block result 32 func NewFetchBlockResult( 33 start xtime.UnixNano, 34 blocks []xio.BlockReader, 35 err error, 36 ) FetchBlockResult { 37 return FetchBlockResult{ 38 Start: start, 39 Blocks: blocks, 40 Err: err, 41 } 42 } 43 44 type fetchBlockResultByTimeAscending []FetchBlockResult 45 46 func (e fetchBlockResultByTimeAscending) Len() int { return len(e) } 47 func (e fetchBlockResultByTimeAscending) Swap(i, j int) { e[i], e[j] = e[j], e[i] } 48 func (e fetchBlockResultByTimeAscending) Less(i, j int) bool { return e[i].Start.Before(e[j].Start) } 49 50 // SortFetchBlockResultByTimeAscending sorts fetch block results in time ascending order 51 func SortFetchBlockResultByTimeAscending(results []FetchBlockResult) { 52 sort.Sort(fetchBlockResultByTimeAscending(results)) 53 } 54 55 // NewFetchBlockMetadataResult creates a new fetch block metadata result. 56 func NewFetchBlockMetadataResult( 57 start xtime.UnixNano, 58 size int64, 59 checksum *uint32, 60 lastRead xtime.UnixNano, 61 err error, 62 ) FetchBlockMetadataResult { 63 return FetchBlockMetadataResult{ 64 Start: start, 65 Size: size, 66 Checksum: checksum, 67 LastRead: lastRead, 68 Err: err, 69 } 70 } 71 72 type fetchBlockMetadataResultByTimeAscending []FetchBlockMetadataResult 73 74 func (a fetchBlockMetadataResultByTimeAscending) Len() int { return len(a) } 75 func (a fetchBlockMetadataResultByTimeAscending) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 76 func (a fetchBlockMetadataResultByTimeAscending) Less(i, j int) bool { 77 return a[i].Start.Before(a[j].Start) 78 } 79 80 type fetchBlockMetadataResults struct { 81 results []FetchBlockMetadataResult 82 pool FetchBlockMetadataResultsPool 83 } 84 85 // NewFetchBlockMetadataResults creates a non-pooled fetchBlockMetadataResults 86 func NewFetchBlockMetadataResults() FetchBlockMetadataResults { 87 return &fetchBlockMetadataResults{} 88 } 89 90 func newPooledFetchBlockMetadataResults( 91 results []FetchBlockMetadataResult, 92 pool FetchBlockMetadataResultsPool, 93 ) FetchBlockMetadataResults { 94 return &fetchBlockMetadataResults{results: results, pool: pool} 95 } 96 97 func (s *fetchBlockMetadataResults) Add(res FetchBlockMetadataResult) { 98 s.results = append(s.results, res) 99 } 100 101 func (s *fetchBlockMetadataResults) Results() []FetchBlockMetadataResult { 102 return s.results 103 } 104 105 func (s *fetchBlockMetadataResults) Sort() { 106 sort.Sort(fetchBlockMetadataResultByTimeAscending(s.results)) 107 } 108 109 func (s *fetchBlockMetadataResults) Reset() { 110 var zeroed FetchBlockMetadataResult 111 for i := range s.results { 112 s.results[i] = zeroed 113 } 114 s.results = s.results[:0] 115 } 116 117 func (s *fetchBlockMetadataResults) Close() { 118 if s.pool != nil { 119 s.pool.Put(s) 120 } 121 } 122 123 // NewFetchBlocksMetadataResult creates new database blocks metadata 124 func NewFetchBlocksMetadataResult( 125 id ident.ID, 126 tags ident.TagIterator, 127 blocks FetchBlockMetadataResults, 128 ) FetchBlocksMetadataResult { 129 return FetchBlocksMetadataResult{ID: id, Tags: tags, Blocks: blocks} 130 } 131 132 type fetchBlocksMetadataResults struct { 133 results []FetchBlocksMetadataResult 134 pool FetchBlocksMetadataResultsPool 135 } 136 137 // NewFetchBlocksMetadataResults creates a non-pooled FetchBlocksMetadataResults 138 func NewFetchBlocksMetadataResults() FetchBlocksMetadataResults { 139 return &fetchBlocksMetadataResults{} 140 } 141 142 func newPooledFetchBlocksMetadataResults( 143 results []FetchBlocksMetadataResult, 144 pool FetchBlocksMetadataResultsPool, 145 ) FetchBlocksMetadataResults { 146 return &fetchBlocksMetadataResults{results: results, pool: pool} 147 } 148 149 func (s *fetchBlocksMetadataResults) Add(res FetchBlocksMetadataResult) { 150 s.results = append(s.results, res) 151 } 152 153 func (s *fetchBlocksMetadataResults) Results() []FetchBlocksMetadataResult { 154 return s.results 155 } 156 157 func (s *fetchBlocksMetadataResults) Reset() { 158 var zeroed FetchBlocksMetadataResult 159 for i := range s.results { 160 s.results[i] = zeroed 161 } 162 s.results = s.results[:0] 163 } 164 165 func (s *fetchBlocksMetadataResults) Close() { 166 for i := range s.results { 167 if s.results[i].ID != nil { 168 s.results[i].ID.Finalize() 169 s.results[i].ID = nil 170 } 171 if s.results[i].Tags != nil { 172 s.results[i].Tags.Close() 173 s.results[i].Tags = nil 174 } 175 if s.results[i].Blocks != nil { 176 s.results[i].Blocks.Close() 177 s.results[i].Blocks = nil 178 } 179 } 180 if s.pool != nil { 181 s.pool.Put(s) 182 } 183 } 184 185 type filteredBlocksMetadataIter struct { 186 res []FetchBlocksMetadataResult 187 id ident.ID 188 metadata Metadata 189 resIdx int 190 blockIdx int 191 err error 192 } 193 194 // NewFilteredBlocksMetadataIter creates a new filtered blocks metadata 195 // iterator, there's no pooling of the tags returned currently. 196 // Only the repair process uses this currently which is unoptimized. 197 func NewFilteredBlocksMetadataIter( 198 res FetchBlocksMetadataResults, 199 ) FilteredBlocksMetadataIter { 200 return &filteredBlocksMetadataIter{res: res.Results()} 201 } 202 203 func (it *filteredBlocksMetadataIter) Next() bool { 204 if it.err != nil { 205 return false 206 } 207 if it.resIdx >= len(it.res) { 208 return false 209 } 210 blocks := it.res[it.resIdx].Blocks.Results() 211 for it.blockIdx < len(blocks) { 212 block := blocks[it.blockIdx] 213 if block.Err != nil { 214 it.blockIdx++ 215 continue 216 } 217 break 218 } 219 if it.blockIdx >= len(blocks) { 220 it.resIdx++ 221 it.blockIdx = 0 222 return it.Next() 223 } 224 it.id = it.res[it.resIdx].ID 225 block := blocks[it.blockIdx] 226 var tags ident.Tags 227 if tagsIter := it.res[it.resIdx].Tags; tagsIter != nil { 228 for tagsIter.Next() { 229 curr := tagsIter.Current() 230 tags.Append(ident.StringTag(curr.Name.String(), curr.Value.String())) 231 } 232 if err := tagsIter.Err(); err != nil { 233 it.err = err 234 return false 235 } 236 tagsIter.Close() 237 // Set to nil so it doesn't get closed again later and trigger a double-put pooling bug. 238 it.res[it.resIdx].Tags = nil 239 } 240 it.metadata = NewMetadata(it.id, tags, block.Start, 241 block.Size, block.Checksum, block.LastRead) 242 it.blockIdx++ 243 return true 244 } 245 246 func (it *filteredBlocksMetadataIter) Current() (ident.ID, Metadata) { 247 return it.id, it.metadata 248 } 249 250 func (it *filteredBlocksMetadataIter) Err() error { 251 return it.err 252 }