nodes: 0, module; 1, function_definition; 2, function_name:compactor; 3, parameters; 4, block; 5, identifier:conf; 6, expression_statement; 7, comment:# Get the database handle; 8, expression_statement; 9, comment:# Get the limits container; 10, expression_statement; 11, comment:# Get the compactor configuration; 12, expression_statement; 13, comment:# Make sure compaction is enabled; 14, if_statement; 15, comment:# Select the bucket key getter; 16, expression_statement; 17, expression_statement; 18, comment:# Now enter our loop; 19, while_statement; 20, comment:"""
      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.
      """; 21, assignment; 22, assignment; 23, assignment; 24, comparison_operator:get_int(config, 'max_updates', 0) <= 0; 25, comment:# We'll just warn about it, since they could be running; 26, comment:# the compactor with a different configuration file; 27, block; 28, assignment; 29, call; 30, True; 31, comment:# Get a bucket key to compact; 32, block; 33, identifier:db; 34, call; 35, identifier:limit_map; 36, call; 37, identifier:config; 38, subscript; 39, call; 40, integer:0; 41, expression_statement; 42, identifier:key_getter; 43, call; 44, attribute; 45, argument_list; 46, try_statement; 47, comment:# Ignore version 1 keys--they can't be compacted; 48, if_statement; 49, comment:# Get the corresponding limit class; 50, try_statement; 51, expression_statement; 52, comment:# OK, we now have the limit (which we really only need for; 53, comment:# the bucket class); let's compact the bucket; 54, try_statement; 55, attribute; 56, argument_list; 57, identifier:LimitContainer; 58, argument_list; 59, identifier:conf; 60, string; 61, identifier:get_int; 62, argument_list; 63, call; 64, attribute; 65, argument_list; 66, identifier:LOG; 67, identifier:info; 68, string:"Compactor initialized"; 69, block; 70, except_clause; 71, comparison_operator:buck_key.version < 2; 72, block; 73, block; 74, except_clause; 75, call; 76, block; 77, except_clause; 78, else_clause; 79, identifier:conf; 80, identifier:get_database; 81, string; 82, identifier:conf; 83, identifier:db; 84, string_content:compactor; 85, identifier:config; 86, string; 87, integer:0; 88, attribute; 89, argument_list; 90, identifier:GetBucketKey; 91, identifier:factory; 92, identifier:config; 93, identifier:db; 94, expression_statement; 95, as_pattern; 96, comment:# Warn about invalid bucket keys; 97, block; 98, attribute; 99, integer:2; 100, continue_statement; 101, expression_statement; 102, identifier:KeyError; 103, comment:# Warn about missing limits; 104, block; 105, attribute; 106, argument_list; 107, expression_statement; 108, identifier:Exception; 109, block; 110, block; 111, string_content:compactor; 112, string_content:max_updates; 113, identifier:LOG; 114, identifier:warning; 115, concatenated_string; 116, assignment; 117, identifier:ValueError; 118, as_pattern_target; 119, expression_statement; 120, continue_statement; 121, identifier:buck_key; 122, identifier:version; 123, assignment; 124, expression_statement; 125, continue_statement; 126, identifier:LOG; 127, identifier:debug; 128, binary_operator:"Compacting bucket %s" % buck_key; 129, call; 130, expression_statement; 131, expression_statement; 132, string:"Compaction is not enabled.  Enable it by "; 133, string:"setting a positive integer value for "; 134, string:"'compactor.max_updates' in the configuration."; 135, identifier:buck_key; 136, call; 137, identifier:exc; 138, call; 139, identifier:limit; 140, subscript; 141, call; 142, string:"Compacting bucket %s"; 143, identifier:buck_key; 144, identifier:compact_bucket; 145, argument_list; 146, call; 147, call; 148, attribute; 149, argument_list; 150, attribute; 151, argument_list; 152, identifier:limit_map; 153, attribute; 154, attribute; 155, argument_list; 156, identifier:db; 157, identifier:buck_key; 158, identifier:limit; 159, attribute; 160, argument_list; 161, attribute; 162, argument_list; 163, attribute; 164, identifier:decode; 165, call; 166, identifier:LOG; 167, identifier:warning; 168, binary_operator:"Error interpreting bucket key: %s" % exc; 169, identifier:buck_key; 170, identifier:uuid; 171, identifier:LOG; 172, identifier:warning; 173, binary_operator:"Unable to compact bucket for limit %s" %
                          buck_key.uuid; 174, identifier:LOG; 175, identifier:exception; 176, binary_operator:"Failed to compact bucket %s" % buck_key; 177, identifier:LOG; 178, identifier:debug; 179, binary_operator:"Finished compacting bucket %s" % buck_key; 180, identifier:limits; 181, identifier:BucketKey; 182, identifier:key_getter; 183, argument_list; 184, string:"Error interpreting bucket key: %s"; 185, identifier:exc; 186, string:"Unable to compact bucket for limit %s"; 187, attribute; 188, string:"Failed to compact bucket %s"; 189, identifier:buck_key; 190, string:"Finished compacting bucket %s"; 191, identifier:buck_key; 192, identifier:buck_key; 193, identifier:uuid
code: 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)