github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/internal/base/event.go (about) 1 // Copyright 2018 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 base 6 7 import ( 8 "bytes" 9 "fmt" 10 11 "github.com/petermattis/pebble/internal/humanize" 12 ) 13 14 // TableInfo contains the common information for table related events. 15 type TableInfo struct { 16 // Path is the location of the file on disk. 17 Path string 18 // FileNum is the internal DB identifier for the table. 19 FileNum uint64 20 // Size is the size of the file in bytes. 21 Size uint64 22 // Smallest is the smallest internal key in the table. 23 Smallest InternalKey 24 // Largest is the largest internal key in the table. 25 Largest InternalKey 26 // SmallestSeqNum is the smallest sequence number in the table. 27 SmallestSeqNum uint64 28 // LargestSeqNum is the largest sequence number in the table. 29 LargestSeqNum uint64 30 } 31 32 func totalSize(tables []TableInfo) uint64 { 33 var size uint64 34 for i := range tables { 35 size += tables[i].Size 36 } 37 return size 38 } 39 40 // CompactionInfo contains the info for a compaction event. 41 type CompactionInfo struct { 42 // JobID is the ID of the compaction job. 43 JobID int 44 // Reason is the reason for the compaction. 45 Reason string 46 // Input contains the input tables for the compaction. A compaction is 47 // performed from Input.Level to Input.Level+1. Input.Tables[0] contains the 48 // inputs from Input.Level and Input.Tables[1] contains the inputs from 49 // Input.Level+1. 50 Input struct { 51 Level int 52 Tables [2][]TableInfo 53 } 54 // Output contains the output tables generated by the compaction. The output 55 // tables are empty for the compaction begin event. 56 Output struct { 57 Level int 58 Tables []TableInfo 59 } 60 Err error 61 } 62 63 func (i CompactionInfo) String() string { 64 if i.Err != nil { 65 return fmt.Sprintf("[JOB %d] compaction to L%d error: %s", 66 i.JobID, i.Output.Level, i.Err) 67 } 68 69 if len(i.Output.Tables) == 0 { 70 return fmt.Sprintf("[JOB %d] compacting L%d -> L%d: %d+%d (%s + %s)", 71 i.JobID, i.Input.Level, i.Output.Level, 72 len(i.Input.Tables[0]), len(i.Input.Tables[1]), 73 humanize.Uint64(totalSize(i.Input.Tables[0])), 74 humanize.Uint64(totalSize(i.Input.Tables[1]))) 75 } 76 77 return fmt.Sprintf("[JOB %d] compacted L%d -> L%d: %d+%d (%s + %s) -> %d (%s)", 78 i.JobID, i.Input.Level, i.Output.Level, 79 len(i.Input.Tables[0]), len(i.Input.Tables[1]), 80 humanize.Uint64(totalSize(i.Input.Tables[0])), 81 humanize.Uint64(totalSize(i.Input.Tables[1])), 82 len(i.Output.Tables), 83 humanize.Uint64(totalSize(i.Output.Tables))) 84 } 85 86 // FlushInfo contains the info for a flush event. 87 type FlushInfo struct { 88 // JobID is the ID of the flush job. 89 JobID int 90 // Reason is the reason for the flush. 91 Reason string 92 // Output contains the ouptut table generated by the flush. The output info 93 // is empty for the flush begin event. 94 Output []TableInfo 95 Err error 96 } 97 98 func (i FlushInfo) String() string { 99 if i.Err != nil { 100 return fmt.Sprintf("[JOB %d] flush error: %s", i.JobID, i.Err) 101 } 102 103 if len(i.Output) == 0 { 104 return fmt.Sprintf("[JOB %d] flushing to L0", i.JobID) 105 } 106 107 return fmt.Sprintf("[JOB %d] flushed to L0: %d (%s)", i.JobID, 108 len(i.Output), humanize.Uint64(totalSize(i.Output))) 109 } 110 111 // ManifestCreateInfo contains info about a manifest creation event. 112 type ManifestCreateInfo struct { 113 // JobID is the ID of the job the caused the manifest to be created. 114 JobID int 115 Path string 116 // The file number of the new Manifest. 117 FileNum uint64 118 Err error 119 } 120 121 func (i ManifestCreateInfo) String() string { 122 if i.Err != nil { 123 return fmt.Sprintf("[JOB %d] MANIFEST create error: %s", i.JobID, i.Err) 124 } 125 126 return fmt.Sprintf("[JOB %d] MANIFEST created %06d", i.JobID, i.FileNum) 127 } 128 129 // ManifestDeleteInfo contains the info for a Manifest deletion event. 130 type ManifestDeleteInfo struct { 131 // JobID is the ID of the job the caused the Manifest to be deleted. 132 JobID int 133 Path string 134 FileNum uint64 135 Err error 136 } 137 138 func (i ManifestDeleteInfo) String() string { 139 if i.Err != nil { 140 return fmt.Sprintf("[JOB %d] MANIFEST delete error: %s", i.JobID, i.Err) 141 } 142 143 return fmt.Sprintf("[JOB %d] MANIFEST deleted %06d", i.JobID, i.FileNum) 144 } 145 146 // TableCreateInfo contains the info for a table creation event. 147 type TableCreateInfo struct { 148 JobID int 149 // Reason is the reason for the table creation (flushing or compacting). 150 Reason string 151 Path string 152 FileNum uint64 153 } 154 155 func (i TableCreateInfo) String() string { 156 return fmt.Sprintf("[JOB %d] %s: sstable created %06d", i.JobID, i.Reason, i.FileNum) 157 } 158 159 // TableDeleteInfo contains the info for a table deletion event. 160 type TableDeleteInfo struct { 161 JobID int 162 Path string 163 FileNum uint64 164 Err error 165 } 166 167 func (i TableDeleteInfo) String() string { 168 if i.Err != nil { 169 return fmt.Sprintf("[JOB %d] sstable delete error %06d: %s", 170 i.JobID, i.FileNum, i.Err) 171 } 172 return fmt.Sprintf("[JOB %d] sstable deleted %06d", i.JobID, i.FileNum) 173 } 174 175 // TableIngestInfo contains the info for a table ingestion event. 176 type TableIngestInfo struct { 177 // JobID is the ID of the job the caused the table to be ingested. 178 JobID int 179 Tables []struct { 180 TableInfo 181 Level int 182 } 183 // GlobalSeqNum is the sequence number that was assigned to all entries in 184 // the ingested table. 185 GlobalSeqNum uint64 186 Err error 187 } 188 189 func (i TableIngestInfo) String() string { 190 if i.Err != nil { 191 return fmt.Sprintf("[JOB %d] ingest error: %s", i.JobID, i.Err) 192 } 193 194 var buf bytes.Buffer 195 for j := range i.Tables { 196 t := &i.Tables[j] 197 fmt.Fprintf(&buf, "[JOB %d] ingested to L%d (%s)\n", i.JobID, 198 t.Level, humanize.Uint64(t.Size)) 199 } 200 return buf.String() 201 } 202 203 // WALCreateInfo contains info about a WAL creation event. 204 type WALCreateInfo struct { 205 // JobID is the ID of the job the caused the WAL to be created. 206 JobID int 207 Path string 208 // The file number of the new WAL. 209 FileNum uint64 210 // The file number of a previous WAL which was recycled to create this 211 // one. Zero if recycling did not take place. 212 RecycledFileNum uint64 213 Err error 214 } 215 216 func (i WALCreateInfo) String() string { 217 if i.Err != nil { 218 return fmt.Sprintf("[JOB %d] WAL create error: %s", i.JobID, i.Err) 219 } 220 221 if i.RecycledFileNum == 0 { 222 return fmt.Sprintf("[JOB %d] WAL created %06d", i.JobID, i.FileNum) 223 } 224 225 return fmt.Sprintf("[JOB %d] WAL created %06d (recycled %06d)", 226 i.JobID, i.FileNum, i.RecycledFileNum) 227 } 228 229 // WALDeleteInfo contains the info for a WAL deletion event. 230 type WALDeleteInfo struct { 231 // JobID is the ID of the job the caused the WAL to be deleted. 232 JobID int 233 Path string 234 FileNum uint64 235 Err error 236 } 237 238 func (i WALDeleteInfo) String() string { 239 if i.Err != nil { 240 return fmt.Sprintf("[JOB %d] WAL delete error: %s", i.JobID, i.Err) 241 } 242 243 return fmt.Sprintf("[JOB %d] WAL deleted %06d", i.JobID, i.FileNum) 244 } 245 246 // WriteStallBeginInfo contains the info for a write stall begin event. 247 type WriteStallBeginInfo struct { 248 Reason string 249 } 250 251 func (i WriteStallBeginInfo) String() string { 252 return fmt.Sprintf("write stall beginning: %s", i.Reason) 253 } 254 255 // EventListener contains a set of functions that will be invoked when various 256 // significant DB events occur. Note that the functions should not run for an 257 // excessive amount of time as they are invokved synchronously by the DB and 258 // may block continued DB work. For a similar reason it is advisable to not 259 // perform any synchronous calls back into the DB. 260 type EventListener struct { 261 // BackgroundError is invoked whenever an error occurs during a background 262 // operation such as flush or compaction. 263 BackgroundError func(error) 264 265 // CompactionBegin is invoked after the inputs to a compaction have been 266 // determined, but before the compaction has produced any output. 267 CompactionBegin func(CompactionInfo) 268 269 // CompactionEnd is invoked after a compaction has completed and the result 270 // has been installed. 271 CompactionEnd func(CompactionInfo) 272 273 // FlushBegin is invoked after the inputs to a flush have been determined, 274 // but before the flush has produced any output. 275 FlushBegin func(FlushInfo) 276 277 // FlushEnd is invoked after a flush has complated and the result has been 278 // installed. 279 FlushEnd func(FlushInfo) 280 281 // ManifestCreated is invoked after a manifest has been created. 282 ManifestCreated func(ManifestCreateInfo) 283 284 // ManifestDeleted is invoked after a manifest has been deleted. 285 ManifestDeleted func(ManifestDeleteInfo) 286 287 // TableCreated is invoked when a table has been created. 288 TableCreated func(TableCreateInfo) 289 290 // TableDeleted is invoked after a table has been deleted. 291 TableDeleted func(TableDeleteInfo) 292 293 // TableIngested is invoked after an externally created table has been 294 // ingested via a call to DB.Ingest(). 295 TableIngested func(TableIngestInfo) 296 297 // WALCreated is invoked after a WAL has been created. 298 WALCreated func(WALCreateInfo) 299 300 // WALDeleted is invoked after a WAL has been deleted. 301 WALDeleted func(WALDeleteInfo) 302 303 // WriteStallBegin is invoked when writes are intentionally delayed. 304 WriteStallBegin func(WriteStallBeginInfo) 305 306 // WriteStallEnd is invoked when delayed writes are released. 307 WriteStallEnd func() 308 } 309 310 // EnsureDefaults ensures that background error events are logged to the 311 // specified logger if a handler for those events hasn't been otherwise 312 // specified. 313 func (l *EventListener) EnsureDefaults(logger Logger) { 314 if l.BackgroundError == nil { 315 l.BackgroundError = func(err error) { 316 logger.Infof("background error: %s", err) 317 } 318 } 319 } 320 321 // MakeLoggingEventListener creates an EventListener that logs all events to the 322 // specified logger. 323 func MakeLoggingEventListener(logger Logger) EventListener { 324 if logger == nil { 325 logger = defaultLogger{} 326 } 327 328 return EventListener{ 329 BackgroundError: func(err error) { 330 logger.Infof("background error: %s", err) 331 }, 332 CompactionBegin: func(info CompactionInfo) { 333 logger.Infof("%s", info.String()) 334 }, 335 CompactionEnd: func(info CompactionInfo) { 336 logger.Infof("%s", info.String()) 337 }, 338 FlushBegin: func(info FlushInfo) { 339 logger.Infof("%s", info.String()) 340 }, 341 FlushEnd: func(info FlushInfo) { 342 logger.Infof("%s", info.String()) 343 }, 344 ManifestCreated: func(info ManifestCreateInfo) { 345 logger.Infof("%s", info.String()) 346 }, 347 ManifestDeleted: func(info ManifestDeleteInfo) { 348 logger.Infof("%s", info.String()) 349 }, 350 TableCreated: func(info TableCreateInfo) { 351 logger.Infof("%s", info.String()) 352 }, 353 TableDeleted: func(info TableDeleteInfo) { 354 logger.Infof("%s", info.String()) 355 }, 356 TableIngested: func(info TableIngestInfo) { 357 logger.Infof("%s", info.String()) 358 }, 359 WALCreated: func(info WALCreateInfo) { 360 logger.Infof("%s", info.String()) 361 }, 362 WALDeleted: func(info WALDeleteInfo) { 363 logger.Infof("%s", info.String()) 364 }, 365 WriteStallBegin: func(info WriteStallBeginInfo) { 366 logger.Infof("%s", info.String()) 367 }, 368 WriteStallEnd: func() { 369 logger.Infof("write stall ending") 370 }, 371 } 372 }