Line data Source code
1 : // Copyright 2011 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 : // of this source code is governed by a BSD-style license that can be found in 3 : // the LICENSE file. 4 : 5 : package sstable 6 : 7 : import ( 8 : "sync/atomic" 9 : 10 : "github.com/cockroachdb/pebble/sstable/block" 11 : ) 12 : 13 : // FilterMetrics holds metrics for the filter policy. 14 : type FilterMetrics struct { 15 : // The number of hits for the filter policy. This is the 16 : // number of times the filter policy was successfully used to avoid access 17 : // of a data block. 18 : Hits int64 19 : // The number of misses for the filter policy. This is the number of times 20 : // the filter policy was checked but was unable to filter an access of a data 21 : // block. 22 : Misses int64 23 : } 24 : 25 : // FilterMetricsTracker is used to keep track of filter metrics. It contains the 26 : // same metrics as FilterMetrics, but they can be updated atomically. An 27 : // instance of FilterMetricsTracker can be passed to a Reader as a ReaderOption. 28 : type FilterMetricsTracker struct { 29 : // See FilterMetrics.Hits. 30 : hits atomic.Int64 31 : // See FilterMetrics.Misses. 32 : misses atomic.Int64 33 : } 34 : 35 : var _ ReaderOption = (*FilterMetricsTracker)(nil) 36 : 37 2 : func (m *FilterMetricsTracker) readerApply(r *Reader) { 38 2 : if r.tableFilter != nil { 39 2 : r.tableFilter.metrics = m 40 2 : } 41 : } 42 : 43 : // Load returns the current values as FilterMetrics. 44 2 : func (m *FilterMetricsTracker) Load() FilterMetrics { 45 2 : return FilterMetrics{ 46 2 : Hits: m.hits.Load(), 47 2 : Misses: m.misses.Load(), 48 2 : } 49 2 : } 50 : 51 : // BlockHandleWithProperties is used for data blocks and first/lower level 52 : // index blocks, since they can be annotated using BlockPropertyCollectors. 53 : type BlockHandleWithProperties struct { 54 : block.Handle 55 : Props []byte 56 : } 57 : 58 : type filterWriter interface { 59 : addKey(key []byte) 60 : finish() ([]byte, error) 61 : metaName() string 62 : policyName() string 63 : } 64 : 65 : type tableFilterReader struct { 66 : policy FilterPolicy 67 : metrics *FilterMetricsTracker 68 : } 69 : 70 2 : func newTableFilterReader(policy FilterPolicy) *tableFilterReader { 71 2 : return &tableFilterReader{ 72 2 : policy: policy, 73 2 : metrics: nil, 74 2 : } 75 2 : } 76 : 77 2 : func (f *tableFilterReader) mayContain(data, key []byte) bool { 78 2 : mayContain := f.policy.MayContain(TableFilter, data, key) 79 2 : if f.metrics != nil { 80 2 : if mayContain { 81 2 : f.metrics.misses.Add(1) 82 2 : } else { 83 2 : f.metrics.hits.Add(1) 84 2 : } 85 : } 86 2 : return mayContain 87 : } 88 : 89 : type tableFilterWriter struct { 90 : policy FilterPolicy 91 : writer FilterWriter 92 : // count is the count of the number of keys added to the filter. 93 : count int 94 : } 95 : 96 2 : func newTableFilterWriter(policy FilterPolicy) *tableFilterWriter { 97 2 : return &tableFilterWriter{ 98 2 : policy: policy, 99 2 : writer: policy.NewWriter(TableFilter), 100 2 : } 101 2 : } 102 : 103 2 : func (f *tableFilterWriter) addKey(key []byte) { 104 2 : f.count++ 105 2 : f.writer.AddKey(key) 106 2 : } 107 : 108 2 : func (f *tableFilterWriter) finish() ([]byte, error) { 109 2 : if f.count == 0 { 110 2 : return nil, nil 111 2 : } 112 2 : return f.writer.Finish(nil), nil 113 : } 114 : 115 2 : func (f *tableFilterWriter) metaName() string { 116 2 : return "fullfilter." + f.policy.Name() 117 2 : } 118 : 119 2 : func (f *tableFilterWriter) policyName() string { 120 2 : return f.policy.Name() 121 2 : }