Line data Source code
1 : // Copyright 2020 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 manifest 6 : 7 : import ( 8 : "fmt" 9 : "math" 10 : 11 : "github.com/cockroachdb/redact" 12 : ) 13 : 14 : // Layer represents a section of the logical sstable hierarchy. It can represent: 15 : // - a level L1 through L6, or 16 : // - the entire L0 level, or 17 : // - a specific L0 sublevel, or 18 : // - the layer of flushable ingests (which is conceptually above the LSM). 19 : type Layer struct { 20 : kind layerKind 21 : value uint16 22 : } 23 : 24 : // Level returns a Layer that represents an entire level (L0 through L6). 25 2 : func Level(level int) Layer { 26 2 : if level < 0 || level >= NumLevels { 27 0 : panic("invalid level") 28 : } 29 2 : return Layer{ 30 2 : kind: levelLayer, 31 2 : value: uint16(level), 32 2 : } 33 : } 34 : 35 : // L0Sublevel returns a Layer that represents a specific L0 sublevel. 36 2 : func L0Sublevel(sublevel int) Layer { 37 2 : // Note: Pebble stops writes once we get to 1000 sublevels. 38 2 : if sublevel < 0 || sublevel > math.MaxUint16 { 39 0 : panic("invalid sublevel") 40 : } 41 2 : return Layer{ 42 2 : kind: l0SublevelLayer, 43 2 : value: uint16(sublevel), 44 2 : } 45 : } 46 : 47 : // FlushableIngestsLayer returns a Layer that represents the flushable ingests 48 : // layer (which is logically above L0). 49 2 : func FlushableIngestsLayer() Layer { 50 2 : return Layer{ 51 2 : kind: flushableIngestsLayer, 52 2 : } 53 2 : } 54 : 55 : // IsSet returns true if l has been initialized. 56 2 : func (l Layer) IsSet() bool { 57 2 : return l.kind != 0 58 2 : } 59 : 60 : // IsFlushableIngests returns true if the layer represents flushable ingests. 61 2 : func (l Layer) IsFlushableIngests() bool { 62 2 : return l.kind == flushableIngestsLayer 63 2 : } 64 : 65 : // IsL0Sublevel returns true if the layer represents an L0 sublevel. 66 0 : func (l Layer) IsL0Sublevel() bool { 67 0 : return l.kind == l0SublevelLayer 68 0 : } 69 : 70 : // Level returns the level for the layer. Must not be called if 71 : // the layer represents flushable ingests. 72 2 : func (l Layer) Level() int { 73 2 : switch l.kind { 74 2 : case levelLayer: 75 2 : return int(l.value) 76 2 : case l0SublevelLayer: 77 2 : return 0 78 0 : case flushableIngestsLayer: 79 0 : panic("flushable ingests layer") 80 0 : default: 81 0 : panic("invalid layer") 82 : } 83 : } 84 : 85 : // Sublevel returns the L0 sublevel. Can only be called if the layer represents 86 : // an L0 sublevel. 87 0 : func (l Layer) Sublevel() int { 88 0 : if !l.IsL0Sublevel() { 89 0 : panic("not an L0 sublevel layer") 90 : } 91 0 : return int(l.value) 92 : } 93 : 94 2 : func (l Layer) String() string { 95 2 : switch l.kind { 96 2 : case levelLayer: 97 2 : return fmt.Sprintf("L%d", l.value) 98 2 : case l0SublevelLayer: 99 2 : return fmt.Sprintf("L0.%d", l.value) 100 2 : case flushableIngestsLayer: 101 2 : return "flushable-ingests" 102 0 : default: 103 0 : return "unknown" 104 : } 105 : } 106 : 107 : // SafeFormat implements redact.SafeFormatter. 108 1 : func (l Layer) SafeFormat(s redact.SafePrinter, verb rune) { 109 1 : s.SafeString(redact.SafeString(l.String())) 110 1 : } 111 : 112 : type layerKind uint8 113 : 114 : const ( 115 : // Entire level: value contains the level number (0 through 6). 116 : levelLayer layerKind = iota + 1 117 : // L0 sublevel: value contains the sublevel number. 118 : l0SublevelLayer 119 : // Flushable ingests layer: value is unused. 120 : flushableIngestsLayer 121 : )