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 1 : func Level(level int) Layer { 26 1 : if level < 0 || level >= NumLevels { 27 0 : panic("invalid level") 28 : } 29 1 : return Layer{ 30 1 : kind: levelLayer, 31 1 : value: uint16(level), 32 1 : } 33 : } 34 : 35 : // L0Sublevel returns a Layer that represents a specific L0 sublevel. 36 1 : func L0Sublevel(sublevel int) Layer { 37 1 : // Note: Pebble stops writes once we get to 1000 sublevels. 38 1 : if sublevel < 0 || sublevel > math.MaxUint16 { 39 0 : panic("invalid sublevel") 40 : } 41 1 : return Layer{ 42 1 : kind: l0SublevelLayer, 43 1 : value: uint16(sublevel), 44 1 : } 45 : } 46 : 47 : // FlushableIngestsLayer returns a Layer that represents the flushable ingests 48 : // layer (which is logically above L0). 49 1 : func FlushableIngestsLayer() Layer { 50 1 : return Layer{ 51 1 : kind: flushableIngestsLayer, 52 1 : } 53 1 : } 54 : 55 : // IsSet returns true if l has been initialized. 56 1 : func (l Layer) IsSet() bool { 57 1 : return l.kind != 0 58 1 : } 59 : 60 : // IsFlushableIngests returns true if the layer represents flushable ingests. 61 1 : func (l Layer) IsFlushableIngests() bool { 62 1 : return l.kind == flushableIngestsLayer 63 1 : } 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 1 : func (l Layer) Level() int { 73 1 : switch l.kind { 74 1 : case levelLayer: 75 1 : return int(l.value) 76 1 : case l0SublevelLayer: 77 1 : 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 1 : func (l Layer) String() string { 95 1 : switch l.kind { 96 1 : case levelLayer: 97 1 : return fmt.Sprintf("L%d", l.value) 98 1 : case l0SublevelLayer: 99 1 : return fmt.Sprintf("L0.%d", l.value) 100 1 : case flushableIngestsLayer: 101 1 : return "flushable-ingests" 102 0 : default: 103 0 : return "unknown" 104 : } 105 : } 106 : 107 : // SafeFormat implements redact.SafeFormatter. 108 0 : func (l Layer) SafeFormat(s redact.SafePrinter, verb rune) { 109 0 : s.SafeString(redact.SafeString(l.String())) 110 0 : } 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 : )