docs: public Deferred<Object> shutdown() {
      final ArrayList<Deferred<Object>> deferreds =
        new ArrayList<Deferred<Object>>();
  
      final class FinalShutdown implements Callback<Object, Object> {
        @Override
        public Object call(Object result) throws Exception {
          if (result instanceof Exception) {
            LOG.error("A previous shutdown failed", (Exception)result);
          }
          final Set<Timeout> timeouts = timer.stop();
          // TODO - at some point we should clean these up.
          if (timeouts.size() > 0) {
            LOG.warn("There were " + timeouts.size() + " timer tasks queued");
          }
          LOG.info("Completed shutting down the TSDB");
          return Deferred.fromResult(null);
        }
      }
  
      final class SEHShutdown implements Callback<Object, Object> {
        @Override
        public Object call(Object result) throws Exception {
          if (result instanceof Exception) {
            LOG.error("Shutdown of the HBase client failed", (Exception)result);
          }
          LOG.info("Shutting down storage exception handler plugin: " +
              storage_exception_handler.getClass().getCanonicalName());
          return storage_exception_handler.shutdown().addBoth(new FinalShutdown());
        }
        @Override
        public String toString() {
          return "SEHShutdown";
        }
      }
  
      final class HClientShutdown implements Callback<Deferred<Object>, ArrayList<Object>> {
  	public Deferred<Object> call(final ArrayList<Object> args) {
          if (storage_exception_handler != null) {
            return client.shutdown().addBoth(new SEHShutdown());
          }
          return client.shutdown().addBoth(new FinalShutdown());
        }
  	public String toString() {
          return "shutdown HBase client";
        }
      }
  
      final class ShutdownErrback implements Callback<Object, Exception> {
  	public Object call(final Exception e) {
          final Logger LOG = LoggerFactory.getLogger(ShutdownErrback.class);
          if (e instanceof DeferredGroupException) {
            final DeferredGroupException ge = (DeferredGroupException) e;
            for (final Object r : ge.results()) {
              if (r instanceof Exception) {
                LOG.error("Failed to shutdown the TSD", (Exception) r);
              }
            }
          } else {
            LOG.error("Failed to shutdown the TSD", e);
          }
          return new HClientShutdown().call(null);
        }
  	public String toString() {
          return "shutdown HBase client after error";
        }
      }
  
      final class CompactCB implements Callback<Object, ArrayList<Object>> {
  	public Object call(ArrayList<Object> compactions) throws Exception {
          return null;
        }
      }
  
      if (config.enable_compactions()) {
        LOG.info("Flushing compaction queue");
        deferreds.add(compactionq.flush().addCallback(new CompactCB()));
      }
      if (startup != null) {
        LOG.info("Shutting down startup plugin: " +
                startup.getClass().getCanonicalName());
        deferreds.add(startup.shutdown());
      }
      if (authentication != null) {
        LOG.info("Shutting down authentication plugin: " +
                authentication.getClass().getCanonicalName());
        deferreds.add(authentication.shutdown());
      }
      if (search != null) {
        LOG.info("Shutting down search plugin: " +
            search.getClass().getCanonicalName());
        deferreds.add(search.shutdown());
      }
      if (rt_publisher != null) {
        LOG.info("Shutting down RT plugin: " +
            rt_publisher.getClass().getCanonicalName());
        deferreds.add(rt_publisher.shutdown());
      }
      if (meta_cache != null) {
        LOG.info("Shutting down meta cache plugin: " +
            meta_cache.getClass().getCanonicalName());
        deferreds.add(meta_cache.shutdown());
      }
      if (storage_exception_handler != null) {
        LOG.info("Shutting down storage exception handler plugin: " +
            storage_exception_handler.getClass().getCanonicalName());
        deferreds.add(storage_exception_handler.shutdown());
      }
      if (ts_filter != null) {
        LOG.info("Shutting down time series filter plugin: " +
            ts_filter.getClass().getCanonicalName());
        deferreds.add(ts_filter.shutdown());
      }
      if (uid_filter != null) {
        LOG.info("Shutting down UID filter plugin: " +
            uid_filter.getClass().getCanonicalName());
        deferreds.add(uid_filter.shutdown());
      }
  
      // wait for plugins to shutdown before we close the client
      return deferreds.size() > 0
        ? Deferred.group(deferreds).addCallbackDeferring(new HClientShutdown())
            .addErrback(new ShutdownErrback())
        : new HClientShutdown().call(null);
    }