Esempio n. 1
0
/*
 * compactdb_start - Compact classes   
 *    return: error code
 *    verbose_flag(in):
 *    delete_old_repr_flag(in): delete old class representations from catalog
 *    input_filename(in): classes file name
 *    input_class_names(in): classes list
 *    input_class_length(in): classes list length
 *    max_processed_space(in): maximum space to process for one iteration
 */
static int
compactdb_start (bool verbose_flag, bool delete_old_repr_flag,
		 char *input_filename,
		 char **input_class_names, int input_class_length,
		 int max_processed_space, int instance_lock_timeout,
		 int class_lock_timeout, DB_TRAN_ISOLATION tran_isolation)
{
  int status = NO_ERROR;
  OID **class_oids = NULL, *next_oid = NULL;
  int i, num_classes = 0;
  LIST_MOPS *class_table = NULL;
  OID last_processed_class_oid, last_processed_oid;
  int *total_objects = NULL, *iteration_total_objects = NULL;
  int *failed_objects = NULL, *iteration_failed_objects = NULL;
  int *modified_objects = NULL, *iteration_modified_objects = NULL;
  char *incomplete_processing = NULL;
  int *big_objects = NULL, *iteration_big_objects = NULL;
  int *initial_last_repr = NULL;
  MOP *class_mops = NULL;
  int last_completed_class_index, temp_index;
  int num_class_mops = 0;
  SM_CLASS *class_ptr = NULL;
  int num_classes_fully_compacted = 0;
  char *class_name = NULL;
  MOP *processed_class_mops = NULL;

  if (input_filename && input_class_names && input_class_length > 0)
    {
      return ER_FAILED;
    }

  status = compact_db_start ();
  if (status != NO_ERROR)
    {
      if (status == ER_COMPACTDB_ALREADY_STARTED)
	{
	  printf (msgcat_message (MSGCAT_CATALOG_UTILS,
				  MSGCAT_UTIL_SET_COMPACTDB,
				  COMPACTDB_MSG_ALREADY_STARTED));
	}

      return ER_FAILED;
    }

  tran_reset_wait_times ((float) class_lock_timeout);
  if (input_class_names && input_class_length > 0)
    {
      status = get_class_mops (input_class_names, input_class_length,
			       &class_mops, &num_class_mops);
      if (status != NO_ERROR)
	{
	  goto error;
	}
    }
  else if (input_filename)
    {
      status = get_class_mops_from_file (input_filename, &class_mops,
					 &num_class_mops);
      if (status != NO_ERROR)
	{
	  goto error;
	}
    }
  else
    {
      class_table =
	locator_get_all_mops (sm_Root_class_mop, DB_FETCH_QUERY_READ);
      if (!class_table)
	{
	  status = ER_FAILED;
	  goto error;
	}

      class_mops = class_table->mops;
      num_class_mops = class_table->num;
    }

  class_oids = (OID **) malloc (DB_SIZEOF (OID *) * (num_class_mops));
  if (class_oids == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  for (i = 0; i < num_class_mops; i++)
    {
      class_oids[i] = NULL;
    }

  processed_class_mops = (DB_OBJECT **) malloc (DB_SIZEOF (DB_OBJECT *) *
						(num_class_mops));
  if (processed_class_mops == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  for (i = 0; i < num_class_mops; i++)
    {
      processed_class_mops[i] = NULL;
    }

  num_classes = 0;
  for (i = 0; i < num_class_mops; i++)
    {
      ws_find (class_mops[i], (MOBJ *) & class_ptr);
      if (class_ptr == NULL)
	{
	  continue;
	}

      if (class_ptr->class_type != SM_CLASS_CT)
	{
	  continue;
	}

      class_oids[num_classes] = ws_oid (class_mops[i]);
      if (class_oids[num_classes] != NULL)
	{
	  processed_class_mops[num_classes] = class_mops[i];
	  num_classes++;
	}
    }

  if (num_classes == 0)
    {
      printf (msgcat_message (MSGCAT_CATALOG_UTILS,
			      MSGCAT_UTIL_SET_COMPACTDB,
			      COMPACTDB_MSG_NOTHING_TO_PROCESS));
      goto error;
    }

  total_objects = (int *) malloc (num_classes * sizeof (int));
  if (total_objects == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  iteration_total_objects = (int *) malloc (num_classes * sizeof (int));
  if (iteration_total_objects == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  failed_objects = (int *) malloc (num_classes * sizeof (int));
  if (failed_objects == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  iteration_failed_objects = (int *) malloc (num_classes * sizeof (int));
  if (iteration_failed_objects == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  modified_objects = (int *) malloc (num_classes * sizeof (int));
  if (modified_objects == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  iteration_modified_objects = (int *) malloc (num_classes * sizeof (int));
  if (iteration_modified_objects == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  big_objects = (int *) malloc (num_classes * sizeof (int));
  if (big_objects == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  iteration_big_objects = (int *) malloc (num_classes * sizeof (int));
  if (iteration_big_objects == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  initial_last_repr = (int *) malloc (num_classes * sizeof (int));
  if (initial_last_repr == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  incomplete_processing = (char *) malloc (num_classes * sizeof (char));
  if (incomplete_processing == NULL)
    {
      status = ER_FAILED;
      goto error;
    }

  for (i = 0; i < num_classes; i++)
    {
      total_objects[i] = 0;
      failed_objects[i] = 0;
      modified_objects[i] = 0;
      big_objects[i] = 0;
      incomplete_processing[i] = 0;
      initial_last_repr[i] = NULL_REPRID;
    }

  for (i = 0; i < num_class_mops; i++)
    {
      status = locator_flush_all_instances (class_mops[i], true);
      if (status != NO_ERROR)
	{
	  goto error;
	}
    }

  status = db_commit_transaction ();
  if (status != NO_ERROR)
    {
      goto error;
    }

  COPY_OID (&last_processed_class_oid, class_oids[0]);
  OID_SET_NULL (&last_processed_oid);
  temp_index = -1;
  last_completed_class_index = -1;

  if (verbose_flag)
    {
      printf (msgcat_message (MSGCAT_CATALOG_UTILS,
			      MSGCAT_UTIL_SET_COMPACTDB,
			      COMPACTDB_MSG_PASS1));
    }

  while (true)
    {
      status = db_set_isolation (tran_isolation);
      if (status != NO_ERROR)
	{
	  if (verbose_flag)
	    {
	      printf (msgcat_message (MSGCAT_CATALOG_UTILS,
				      MSGCAT_UTIL_SET_COMPACTDB,
				      COMPACTDB_MSG_ISOLATION_LEVEL_FAILURE));
	    }

	  status = ER_FAILED;
	  goto error;
	}

      status = boot_compact_classes (class_oids, num_classes,
				     max_processed_space,
				     instance_lock_timeout * 1000,
				     class_lock_timeout * 1000,
				     delete_old_repr_flag,
				     &last_processed_class_oid,
				     &last_processed_oid,
				     iteration_total_objects,
				     iteration_failed_objects,
				     iteration_modified_objects,
				     iteration_big_objects,
				     initial_last_repr);

      if (OID_ISNULL (&last_processed_class_oid))
	{
	  temp_index = num_classes;
	}
      else
	{
	  temp_index = find_oid (&last_processed_class_oid,
				 class_oids, num_classes);
	}

      switch (status)
	{
	case NO_ERROR:
	  if (delete_old_repr_flag &&
	      temp_index - 1 > last_completed_class_index)
	    {
	      for (i = last_completed_class_index + 1; i < temp_index; i++)
		{
		  if (initial_last_repr[i] == COMPACTDB_REPR_DELETED)
		    {
		      sm_destroy_representations (processed_class_mops[i]);
		    }
		}
	    }

	  status = db_commit_transaction ();
	  if (status != NO_ERROR)
	    {
	      goto error;
	    }
	  break;

	case ER_LK_UNILATERALLY_ABORTED:
	  status = tran_abort_only_client (false);
	  if (status != NO_ERROR)
	    {
	      goto error;
	    }
	  break;

	case ER_FAILED:
	  status = db_abort_transaction ();
	  if (status != NO_ERROR)
	    {
	      goto error;
	    }
	  break;

	default:
	  db_abort_transaction ();
	  status = ER_FAILED;
	  goto error;
	}

      for (i = 0; i < num_classes; i++)
	{
	  if (iteration_total_objects[i] >= 0)
	    {
	      total_objects[i] += iteration_total_objects[i];
	      failed_objects[i] += iteration_failed_objects[i];
	      modified_objects[i] += iteration_modified_objects[i];
	      big_objects[i] += iteration_big_objects[i];
	    }
	  else
	    {
	      incomplete_processing[i] = iteration_total_objects[i];
	    }
	}

      if (temp_index - 1 > last_completed_class_index)
	{
	  for (i = last_completed_class_index + 1; i < temp_index; i++)
	    {
	      status = db_set_isolation (tran_isolation);
	      if (status != NO_ERROR)
		{
		  if (verbose_flag)
		    {
		      printf (msgcat_message
			      (MSGCAT_CATALOG_UTILS,
			       MSGCAT_UTIL_SET_COMPACTDB,
			       COMPACTDB_MSG_ISOLATION_LEVEL_FAILURE));
		    }

		  status = ER_FAILED;
		  goto error;
		}

	      tran_reset_wait_times ((float) class_lock_timeout);
	      show_statistics
		(class_oids[i],
		 incomplete_processing[i] != COMPACTDB_LOCKED_CLASS,
		 incomplete_processing[i] != COMPACTDB_INVALID_CLASS,
		 incomplete_processing[i] != COMPACTDB_UNPROCESSED_CLASS,
		 total_objects[i], failed_objects[i],
		 modified_objects[i], big_objects[i],
		 delete_old_repr_flag,
		 initial_last_repr[i] == COMPACTDB_REPR_DELETED);

	      db_commit_transaction ();
	    }

	  last_completed_class_index = temp_index - 1;
	}

      if (OID_ISNULL (&last_processed_class_oid))
	{
	  break;
	}
    }

  if (verbose_flag)
    {
      printf (msgcat_message (MSGCAT_CATALOG_UTILS,
			      MSGCAT_UTIL_SET_COMPACTDB,
			      COMPACTDB_MSG_PASS2));
    }
  status = do_reclaim_addresses (class_oids, num_classes,
				 &num_classes_fully_compacted, verbose_flag,
				 (float) class_lock_timeout);
  if (status != NO_ERROR)
    {
      goto error;
    }

  if (verbose_flag)
    {
      printf (msgcat_message (MSGCAT_CATALOG_UTILS,
			      MSGCAT_UTIL_SET_COMPACTDB,
			      COMPACTDB_MSG_PASS3));
    }

  for (i = 0; i < num_classes; i++)
    {
      status = db_set_isolation (tran_isolation);
      if (status != NO_ERROR)
	{
	  if (verbose_flag)
	    {
	      printf (msgcat_message
		      (MSGCAT_CATALOG_UTILS,
		       MSGCAT_UTIL_SET_COMPACTDB,
		       COMPACTDB_MSG_ISOLATION_LEVEL_FAILURE));
	    }

	  status = ER_FAILED;
	  goto error;
	}

      tran_reset_wait_times ((float) class_lock_timeout);

      status = boot_heap_compact (class_oids[i]);
      switch (status)
	{
	case NO_ERROR:
	  status = db_commit_transaction ();
	  if (status != NO_ERROR)
	    {
	      goto error;
	    }
	  break;

	case ER_LK_UNILATERALLY_ABORTED:
	  status = tran_abort_only_client (false);
	  if (status != NO_ERROR)
	    {
	      goto error;
	    }
	  break;

	default:
	  status = db_abort_transaction ();
	  if (status != NO_ERROR)
	    {
	      goto error;
	    }
	  break;
	}

      class_name = get_name_from_class_oid (class_oids[i]);
      if (class_name == NULL)
	{
	  printf (msgcat_message (MSGCAT_CATALOG_UTILS,
				  MSGCAT_UTIL_SET_COMPACTDB,
				  COMPACTDB_MSG_UNKNOWN_CLASS_NAME));
	}
      else
	{
	  printf (msgcat_message (MSGCAT_CATALOG_UTILS,
				  MSGCAT_UTIL_SET_COMPACTDB,
				  COMPACTDB_MSG_CLASS), class_name);
	}

      if (status != NO_ERROR)
	{
	  printf (msgcat_message (MSGCAT_CATALOG_UTILS,
				  MSGCAT_UTIL_SET_COMPACTDB,
				  COMPACTDB_MSG_HEAP_COMPACT_FAILED));
	}
      else
	{
	  printf (msgcat_message (MSGCAT_CATALOG_UTILS,
				  MSGCAT_UTIL_SET_COMPACTDB,
				  COMPACTDB_MSG_HEAP_COMPACT_SUCCEEDED));
	}

      if (class_name)
	{
	  free (class_name);
	  class_name = NULL;
	}

      db_commit_transaction ();
    }

error:
  if (class_oids)
    {
      free_and_init (class_oids);
    }

  if (processed_class_mops)
    {
      free_and_init (processed_class_mops);
    }

  if (total_objects)
    {
      free_and_init (total_objects);
    }

  if (iteration_total_objects)
    {
      free_and_init (iteration_total_objects);
    }

  if (failed_objects)
    {
      free_and_init (failed_objects);
    }

  if (iteration_failed_objects)
    {
      free_and_init (iteration_failed_objects);
    }

  if (modified_objects)
    {
      free_and_init (modified_objects);
    }

  if (iteration_modified_objects)
    {
      free_and_init (iteration_modified_objects);
    }

  if (big_objects)
    {
      free_and_init (big_objects);
    }

  if (iteration_big_objects)
    {
      free_and_init (iteration_big_objects);
    }

  if (initial_last_repr)
    {
      free_and_init (initial_last_repr);
    }

  if (incomplete_processing)
    {
      free_and_init (incomplete_processing);
    }

  if (class_table)
    {
      locator_free_list_mops (class_table);
    }
  else
    {
      if (class_mops)
	{
	  for (i = 0; i < num_class_mops; i++)
	    {
	      class_mops[i] = NULL;
	    }

	  free_and_init (class_mops);
	}
    }

  compact_db_stop ();

  return status;
}
Esempio n. 2
0
/*
 * process_value () - process a value
 *
 * return : error status
 *  value(in,out) - the processed value
 *
 */
static int
process_value (DB_VALUE * value)
{
  int return_value = 0;

  switch (DB_VALUE_TYPE (value))
    {
    case DB_TYPE_OID:
      {
	OID *ref_oid;
	OID ref_class_oid;

	ref_oid = DB_GET_OID (value);

	if (OID_ISNULL (ref_oid))
	  {
	    break;
	  }

	if (!heap_get_class_oid (NULL, ref_oid, &ref_class_oid))
	  {
	    OID_SET_NULL (ref_oid);
	    return_value = 1;
	    break;
	  }

	if (is_class (ref_oid, &ref_class_oid))
	  {
	    break;
	  }

#if defined(CUBRID_DEBUG)
	printf (msgcat_message (MSGCAT_CATALOG_UTILS,
				MSGCAT_UTIL_SET_COMPACTDB,
				COMPACTDB_MSG_REFOID),
		ref_oid->volid, ref_oid->pageid, ref_oid->slotid,
		ref_class_oid.volid, ref_class_oid.pageid,
		ref_class_oid.slotid);
#endif

	if (!heap_does_exist (NULL, ref_oid, &ref_class_oid))
	  {
	    OID_SET_NULL (ref_oid);
	    return_value = 1;
	  }

	break;
      }

    case DB_TYPE_POINTER:
    case DB_TYPE_MULTISET:
    case DB_TYPE_SEQUENCE:
    case DB_TYPE_SET:
      {
	return_value = process_set (DB_GET_SET (value));
	break;
      }

    default:
      break;
    }

  return return_value;
}
Esempio n. 3
0
static int
do_reclaim_class_addresses (const OID class_oid, char **class_name,
			    bool * const any_class_can_be_referenced,
			    bool * const correctly_processed,
			    bool * const addresses_reclaimed,
			    int *const error_while_processing)
{
  DB_OBJECT *class_mop = NULL;
  DB_OBJECT *parent_mop = NULL;
  SM_CLASS *class_ = NULL;
  SM_CLASS *parent_class_ = NULL;
  int error_code = NO_ERROR;
  int skipped_error_code = NO_ERROR;
  bool do_abort_on_error = true;
  bool can_reclaim_addresses = true;
  LIST_MOPS *lmops = NULL;
  HFID *hfid = NULL;

  assert (!OID_ISNULL (&class_oid));
  assert (any_class_can_be_referenced != NULL);
  assert (correctly_processed != NULL);
  assert (addresses_reclaimed != NULL);
  assert (error_while_processing != NULL);
  assert (class_name != NULL);

  *correctly_processed = false;
  *addresses_reclaimed = false;
  *error_while_processing = NO_ERROR;

  error_code = db_commit_transaction ();
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  error_code = db_set_isolation (TRAN_READ_COMMITTED);
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  /*
   * Trying to force an ISX_LOCK on the root class. It somehow happens that
   * we are left with an IX_LOCK in the end...
   */
  if (locator_fetch_class (sm_Root_class_mop, DB_FETCH_QUERY_WRITE) == NULL)
    {
      error_code = ER_FAILED;
      goto error_exit;
    }

  class_mop = db_object ((OID *) (&class_oid));
  if (class_mop == NULL)
    {
      skipped_error_code = ER_FAILED;
      goto error_exit;
    }

  if (!locator_is_class (class_mop, DB_FETCH_WRITE))
    {
      skipped_error_code = ER_FAILED;
      goto error_exit;
    }

  /*
   * We need an X_LOCK on the class to process as early as possible so that
   * other transactions don't add references to it in the schema.
   */
  class_ = (SM_CLASS *) locator_fetch_class (class_mop, DB_FETCH_WRITE);
  if (class_ == NULL)
    {
      skipped_error_code = er_errid ();
      goto error_exit;
    }

  assert (*class_name == NULL);
  *class_name = strdup (class_->header.name);
  if (*class_name == NULL)
    {
      error_code = ER_FAILED;
      goto error_exit;
    }

  if (class_->partition_of != NULL)
    {
      /*
       * If the current class is a partition of a partitioned class we need
       * to get its parent partitioned table and check for references to its
       * parent too. If table tbl has partition tbl__p__p0, a reference to tbl
       * can point to tbl__p__p0 instances too.
       */
      skipped_error_code = do_get_partition_parent (class_mop, &parent_mop);
      if (skipped_error_code != NO_ERROR)
	{
	  goto error_exit;
	}
      if (parent_mop != NULL)
	{
	  parent_class_ =
	    (SM_CLASS *) locator_fetch_class (parent_mop, DB_FETCH_WRITE);
	  if (parent_class_ == NULL)
	    {
	      skipped_error_code = er_errid ();
	      goto error_exit;
	    }
	}
    }

  skipped_error_code = locator_flush_all_instances (class_mop, true);
  if (skipped_error_code != NO_ERROR)
    {
      goto error_exit;
    }

  if (class_->class_type != SM_CLASS_CT)
    {
      can_reclaim_addresses = false;
    }
  else
    {
      hfid = sm_heap ((MOBJ) class_);
      if (HFID_IS_NULL (hfid))
	{
	  can_reclaim_addresses = false;
	}
    }

  if (class_->flags & SM_CLASSFLAG_SYSTEM)
    {
      /*
       * It should be safe to process system classes also but we skip them for
       * now. Please note that class_instances_can_be_referenced () does not
       * check for references from system classes.
       * If this is ever changed please consider the impact of reusing system
       * objects OIDs.
       */
      can_reclaim_addresses = false;
    }
  else if (class_->flags & SM_CLASSFLAG_REUSE_OID)
    {
      /*
       * Nobody should be able to hold references to reusable OID tables so it
       * should be safe to reclaim their OIDs and pages no matter what.
       */
      can_reclaim_addresses = true;
    }
  else
    {
      if (*any_class_can_be_referenced)
	{
	  /*
	   * Some class attribute has OBJECT or SET OF OBJECT as the domain.
	   * This means it can point to instances of any class so we're not
	   * safe reclaiming OIDs.
	   */
	  can_reclaim_addresses = false;
	}
      else
	{
	  bool class_can_be_referenced = false;

	  /*
	   * IS_LOCK should be enough for what we need but
	   * locator_get_all_class_mops seems to lock the instances with the
	   * lock that it has on their class. So we end up with IX_LOCK on all
	   * classes in the schema...
	   */

	  lmops = locator_get_all_class_mops (DB_FETCH_CLREAD_INSTREAD,
					      is_not_system_class);
	  if (lmops == NULL)
	    {
	      skipped_error_code = ER_FAILED;
	      goto error_exit;
	    }

	  skipped_error_code =
	    class_instances_can_be_referenced (class_mop, parent_mop,
					       &class_can_be_referenced,
					       any_class_can_be_referenced,
					       lmops->mops, lmops->num);
	  if (skipped_error_code != NO_ERROR)
	    {
	      goto error_exit;
	    }
	  /*
	   * If some attribute has OBJECT or the current class as its domain
	   * then it's not safe to reclaim the OIDs as some of the references
	   * might point to deleted objects. We skipped the system classes as
	   * they should not point to any instances of the non-system classes.
	   */
	  can_reclaim_addresses = !class_can_be_referenced &&
	    !*any_class_can_be_referenced;
	  if (lmops != NULL)
	    {
	      /*
	       * It should be safe now to release all the locks we hold on the
	       * schema classes (except for the X_LOCK on the current class).
	       * However, we don't currently have a way of releasing those
	       * locks so we're stuck with them till the end of the current
	       * transaction.
	       */
	      locator_free_list_mops (lmops);
	      lmops = NULL;
	    }
	}
    }

  if (can_reclaim_addresses)
    {
      assert (hfid != NULL && !HFID_IS_NULL (hfid));

      skipped_error_code = heap_reclaim_addresses (hfid);
      if (skipped_error_code != NO_ERROR)
	{
	  goto error_exit;
	}
      *addresses_reclaimed = true;
    }

  error_code = db_commit_transaction ();
  if (error_code != NO_ERROR)
    {
      goto error_exit;
    }

  assert (error_code == NO_ERROR && skipped_error_code == NO_ERROR);
  *correctly_processed = true;
  class_mop = NULL;
  class_ = NULL;
  parent_mop = NULL;
  parent_class_ = NULL;
  return error_code;

error_exit:
  *error_while_processing = skipped_error_code;
  class_mop = NULL;
  class_ = NULL;
  parent_mop = NULL;
  parent_class_ = NULL;
  if (lmops != NULL)
    {
      locator_free_list_mops (lmops);
      lmops = NULL;
    }
  if (do_abort_on_error)
    {
      int tmp_error_code = NO_ERROR;

      if (skipped_error_code == ER_LK_UNILATERALLY_ABORTED ||
	  error_code == ER_LK_UNILATERALLY_ABORTED)
	{
	  tmp_error_code = tran_abort_only_client (false);
	}
      else
	{
	  tmp_error_code = db_abort_transaction ();
	}
      if (tmp_error_code != NO_ERROR)
	{
	  if (error_code == NO_ERROR)
	    {
	      error_code = tmp_error_code;
	    }
	}
    }
  if (skipped_error_code == NO_ERROR && error_code == NO_ERROR)
    {
      error_code = ER_FAILED;
    }
  return error_code;
}
Esempio n. 4
0
 /*
  * boot_compact_db - compact specified classes
  * HEAP_CACHE_ATTRINFO structure
  *    return: error status
  *    class_oids(in): the classes list
  *    n_classes(in): the class_oids length
  * hfids(in):  the hfid list
  *    space_to_process(in): the space to process
  *    instance_lock_timeout(in): the lock timeout for instances
  *    class_lock_timeout(in): the lock timeout for instances
  *    delete_old_repr(in):  whether to delete the old class representation
  *    last_processed_class_oid(in,out): last processed class oid
  *    last_processed_oid(in,out): last processed oid
  *    total_objects(out): count processed objects for each class
  *    failed_objects(out): count failed objects for each class
  *    modified_objects(out): count modified objects for each class
  *    big_objects(out): count big objects for each class
  *    initial_last_repr_id(in, out): the list of initial last class 
  * representation
  */
int
boot_compact_db (THREAD_ENTRY * thread_p, OID * class_oids, int n_classes,
		 int space_to_process,
		 int instance_lock_timeout,
		 int class_lock_timeout,
		 bool delete_old_repr,
		 OID * last_processed_class_oid,
		 OID * last_processed_oid,
		 int *total_objects, int *failed_objects,
		 int *modified_objects, int *big_objects,
		 int *initial_last_repr_id)
{
  int result = NO_ERROR;
  int i, j, start_index = -1;
  int max_space_to_process, current_tran_index = -1;
  int lock_ret;
  HFID hfid;

  if (boot_can_compact (thread_p) == false)
    {
      return ER_COMPACTDB_ALREADY_STARTED;
    }

  if (class_oids == NULL || n_classes <= 0 ||
      space_to_process <= 0 || last_processed_class_oid == NULL ||
      last_processed_oid == NULL || total_objects == NULL ||
      failed_objects == NULL || modified_objects == NULL ||
      big_objects == NULL || initial_last_repr_id == NULL)
    {
      return ER_QPROC_INVALID_PARAMETER;
    }

  for (start_index = 0; start_index < n_classes; start_index++)
    {
      if (OID_EQ (class_oids + start_index, last_processed_class_oid))
	{
	  break;
	}
    }

  if (start_index == n_classes)
    {
      return ER_QPROC_INVALID_PARAMETER;
    }

  for (i = 0; i < n_classes; i++)
    {
      total_objects[i] = 0;
      failed_objects[i] = 0;
      modified_objects[i] = 0;
      big_objects[i] = 0;
    }

  max_space_to_process = space_to_process;
  for (i = start_index; i < n_classes; i++)
    {
      lock_ret = lock_object_waitsecs (thread_p, class_oids + i,
				       oid_Root_class_oid, IX_LOCK,
				       LK_UNCOND_LOCK, class_lock_timeout);

      if (lock_ret != LK_GRANTED)
	{
	  total_objects[i] = COMPACTDB_LOCKED_CLASS;
	  OID_SET_NULL (last_processed_oid);
	  continue;
	}

      if (heap_get_hfid_from_class_oid (thread_p, class_oids + i, &hfid) !=
	  NO_ERROR)
	{
	  lock_unlock_object (thread_p, class_oids + i, oid_Root_class_oid,
			      IX_LOCK, true);
	  OID_SET_NULL (last_processed_oid);
	  total_objects[i] = COMPACTDB_INVALID_CLASS;
	  continue;
	}

      if (HFID_IS_NULL (&hfid))
	{
	  lock_unlock_object (thread_p, class_oids + i, oid_Root_class_oid,
			      IX_LOCK, true);
	  OID_SET_NULL (last_processed_oid);
	  total_objects[i] = COMPACTDB_INVALID_CLASS;
	  continue;
	}

      if (OID_ISNULL (last_processed_oid))
	{
	  initial_last_repr_id[i] =
	    heap_get_class_repr_id (thread_p, class_oids + i);
	  if (initial_last_repr_id[i] <= 0)
	    {
	      lock_unlock_object (thread_p, class_oids + i,
				  oid_Root_class_oid, IX_LOCK, true);
	      total_objects[i] = COMPACTDB_INVALID_CLASS;
	      continue;
	    }
	}

      if (process_class
	  (thread_p, class_oids + i, &hfid, max_space_to_process,
	   &instance_lock_timeout, &space_to_process,
	   last_processed_oid, total_objects + i,
	   failed_objects + i, modified_objects + i, big_objects + i) !=
	  NO_ERROR)
	{
	  OID_SET_NULL (last_processed_oid);
	  for (j = start_index; j <= i; j++)
	    {
	      total_objects[j] = COMPACTDB_UNPROCESSED_CLASS;
	      failed_objects[j] = 0;
	      modified_objects[j] = 0;
	      big_objects[j] = 0;
	    }

	  result = ER_FAILED;
	  break;
	}

      if (delete_old_repr &&
	  OID_ISNULL (last_processed_oid) && failed_objects[i] == 0 &&
	  heap_get_class_repr_id (thread_p, class_oids + i) ==
	  initial_last_repr_id[i])
	{
	  lock_ret = lock_object_waitsecs (thread_p, class_oids + i,
					   oid_Root_class_oid, X_LOCK,
					   LK_UNCOND_LOCK,
					   class_lock_timeout);
	  if (lock_ret == LK_GRANTED)
	    {
	      if (catalog_drop_old_representations (thread_p, class_oids + i)
		  != NO_ERROR)
		{
		  for (j = start_index; j <= i; j++)
		    {
		      total_objects[j] = COMPACTDB_UNPROCESSED_CLASS;
		      failed_objects[j] = 0;
		      modified_objects[j] = 0;
		      big_objects[j] = 0;
		    }

		  result = ER_FAILED;
		}
	      else
		{
		  initial_last_repr_id[i] = COMPACTDB_REPR_DELETED;
		}

	      break;
	    }
	}

      if (space_to_process == 0)
	{
	  break;
	}
    }

  if (OID_ISNULL (last_processed_oid))
    {
      if (i < n_classes - 1)
	{
	  COPY_OID (last_processed_class_oid, class_oids + i + 1);
	}
      else
	{
	  OID_SET_NULL (last_processed_class_oid);
	}
    }
  else
    {
      COPY_OID (last_processed_class_oid, class_oids + i);
    }

  return result;
}