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  }