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