The compactor daemon.  This fuction watches the sorted set
    containing bucket keys that need to be compacted, performing the
    necessary compaction.

    :param conf: A turnstile.config.Config instance containing the
                 configuration for the compactor daemon.  Note that a
                 ControlDaemon is also started, so appropriate
                 configuration for that must also be present, as must
                 appropriate Redis connection information.

def compactor(conf):
    """
    The compactor daemon.  This fuction watches the sorted set
    containing bucket keys that need to be compacted, performing the
    necessary compaction.

    :param conf: A turnstile.config.Config instance containing the
                 configuration for the compactor daemon.  Note that a
                 ControlDaemon is also started, so appropriate
                 configuration for that must also be present, as must
                 appropriate Redis connection information.
    """

    # Get the database handle
    db = conf.get_database('compactor')

    # Get the limits container
    limit_map = LimitContainer(conf, db)

    # Get the compactor configuration
    config = conf['compactor']

    # Make sure compaction is enabled
    if get_int(config, 'max_updates', 0) <= 0:
        # We'll just warn about it, since they could be running
        # the compactor with a different configuration file
        LOG.warning("Compaction is not enabled.  Enable it by "
                    "setting a positive integer value for "
                    "'compactor.max_updates' in the configuration.")

    # Select the bucket key getter
    key_getter = GetBucketKey.factory(config, db)

    LOG.info("Compactor initialized")

    # Now enter our loop
    while True:
        # Get a bucket key to compact
        try:
            buck_key = limits.BucketKey.decode(key_getter())
        except ValueError as exc:
            # Warn about invalid bucket keys
            LOG.warning("Error interpreting bucket key: %s" % exc)
            continue

        # Ignore version 1 keys--they can't be compacted
        if buck_key.version < 2:
            continue

        # Get the corresponding limit class
        try:
            limit = limit_map[buck_key.uuid]
        except KeyError:
            # Warn about missing limits
            LOG.warning("Unable to compact bucket for limit %s" %
                        buck_key.uuid)
            continue

        LOG.debug("Compacting bucket %s" % buck_key)

        # OK, we now have the limit (which we really only need for
        # the bucket class); let's compact the bucket
        try:
            compact_bucket(db, buck_key, limit)
        except Exception:
            LOG.exception("Failed to compact bucket %s" % buck_key)
        else:
            LOG.debug("Finished compacting bucket %s" % buck_key)