17.4 EventListener 事件监听器

EventListener

EventListener类包含一组回调函数,当发生特定RockSDB事件(如完成刷新或压缩作业)时将调用这些函数。 这样的回调API可以用作构建块,用于开发诸如stats收集器或外部压缩算法之类的自定义功能。 可用的EventListener回调可以在include/rocksdb/listener.h中找到。

如何使用它?

在ColumnFamilyOptions中,有一个名为listener的变量,它允许开发人员添加定制的EventListener来侦听特定rocksdb实例的事件或rocksdb实例的列族事件。

  1. // A vector of EventListeners which call-back functions will be called
  2. // when specific RocksDB event happens.
  3. std::vector<std::shared_ptr<EventListener>> listeners;

要侦听rocksdb实例或rocksdb实例的列族,只需将自定义EventListener添加到ColumnFamilyOptions::listener并使用该选项打开DB:

  1. // listen to a column family of a rocksdb instance
  2. ColumnFamilyOptions cf_options;
  3. ...
  4. cf_options.listeners.emplace_back(new MyListener());

要侦听rocksdb实例的多个列族,可以为每个列族使用单独的侦听器实例,

  1. // one listener for each column family
  2. for (size_t i = 0; i < cf_options.size(); ++i) {
  3. cf_options[i].listeners.emplace_back(new MyListener());
  4. }

或对所有列族使用相同的侦听器实例:

  1. // one same listener for all column families.
  2. EventListener my_listener = new MyListener();
  3. for (size_t i = 0; i < cf_options.size(); ++i) {
  4. cf_options[i].listeners.emplace_back(my_listener);
  5. }

注意,在这两种情况下,除非特别指定的文档,所有EventListener回味必须实现线程安全的方式即使EventListener只听一个列族(例如,假设的情况OnCompactionCompleted()可以由多个线程同时调用一个列族可能完成多个同时压实工作

监听一个特定的事件

所有EventListener回调的默认行为都是no-op。这允许开发人员只关注他们感兴趣的事件。要侦听特定事件,只需实现其相关回调即可。例如,下面的EventListener通过实现OnFlushCompleted()计算自DB打开以来完成的刷新作业的数量:

  1. class FlushCountListener : public EventListener {
  2. public:
  3. FlushCountListener() : flush_count_(0) {}
  4. void OnFlushCompleted(
  5. DB* db, const std::string& name,
  6. const std::string& file_path,
  7. bool triggered_writes_slowdown,
  8. bool triggered_writes_stop) override {
  9. flush_count_++;
  10. }
  11. private:
  12. std::atomic_int flush_count_;
  13. };

线程

所有EventListener回调都将使用涉及该特定事件的实际线程来调用。例如,RocksDB后台刷新线程执行实际的刷新,以调用EventListener::OnFlushCompleted()。 这允许开发人员从EventListener回调中收集线程相关的统计信息,比如通过线程本地变量。

锁定

所有EventListener回调都设计为在当前线程不包含任何DB互斥量的情况下调用。这是为了防止在以复杂的方式使用EventListener回调时出现潜在的死锁和性能问题。 但是,所有EventListener回调函数都不应该在函数返回之前长时间运行,否则RocksDB可能会被阻塞。 例如,不建议在EventListener回调的同一个线程中执行DB::CompactFiles()(因为它可能会运行很长时间)或发出许多DB::Put()(因为在某些情况下Put可能被阻塞)。 但是,在EventListener回调线程之外的线程中执行DB::CompactFiles()和DB::Put()被认为是安全的。