/* * process_class - process a class * HEAP_CACHE_ATTRINFO structure * return: error status * class_oid(in): the class OID * hfid(in): the class HFID * max_space_to_process(in): maximum space to process * instance_lock_timeout(in): the lock timeout for instances * space_to_process(in, out): space to process * last_processed_oid(in, out): last processed oid * total_objects(in, out): count the processed class objects * failed_objects(in, out): count the failed class objects * modified_objects(in, out): count the modified class objects * big_objects(in, out): count the big class objects */ static int process_class (THREAD_ENTRY * thread_p, OID * class_oid, HFID * hfid, int max_space_to_process, int *instance_lock_timeout, int *space_to_process, OID * last_processed_oid, int *total_objects, int *failed_objects, int *modified_objects, int *big_objects) { int nobjects, nfetched, i, j; OID last_oid, prev_oid; LOCK null_lock = NULL_LOCK; LOCK oid_lock = X_LOCK; LC_COPYAREA *fetch_area = NULL; /* Area where objects are received */ struct lc_copyarea_manyobjs *mobjs; /* Describe multiple objects in area */ struct lc_copyarea_oneobj *obj; /* Describe on object in area */ RECDES recdes; HEAP_CACHE_ATTRINFO attr_info; HEAP_SCANCACHE upd_scancache; int ret = NO_ERROR, object_processed; int nfailed_instances = 0; if (class_oid == NULL || hfid == NULL || space_to_process == NULL || *space_to_process <= 0 || *space_to_process > max_space_to_process || last_processed_oid == NULL || total_objects == NULL || failed_objects == NULL || modified_objects == NULL || big_objects == NULL || *total_objects < 0 || *failed_objects < 0) { return ER_FAILED; } nobjects = 0; nfetched = -1; ret = heap_scancache_start_modify (thread_p, &upd_scancache, hfid, class_oid, SINGLE_ROW_UPDATE); if (ret != NO_ERROR) { return ER_FAILED; } ret = heap_attrinfo_start (thread_p, class_oid, -1, NULL, &attr_info); if (ret != NO_ERROR) { heap_scancache_end_modify (thread_p, &upd_scancache); return ER_FAILED; } COPY_OID (&last_oid, last_processed_oid); COPY_OID (&prev_oid, last_processed_oid); while (nobjects != nfetched) { ret = xlocator_lock_and_fetch_all (thread_p, hfid, &oid_lock, instance_lock_timeout, class_oid, &null_lock, &nobjects, &nfetched, &nfailed_instances, &last_oid, &fetch_area); if (ret == NO_ERROR) { (*total_objects) += nfailed_instances; (*failed_objects) += nfailed_instances; if (fetch_area != NULL) { mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (fetch_area); obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs); for (i = 0; i < mobjs->num_objs; i++) { if (obj->length > *space_to_process) { if (*space_to_process == max_space_to_process) { (*total_objects)++; (*big_objects)++; lock_unlock_object (thread_p, &obj->oid, class_oid, oid_lock, true); } else { *space_to_process = 0; COPY_OID (last_processed_oid, &prev_oid); for (j = i; j < mobjs->num_objs; j++) { lock_unlock_object (thread_p, &obj->oid, class_oid, oid_lock, true); obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj); } if (fetch_area) { locator_free_copy_area (fetch_area); } goto end; } } else { *space_to_process -= obj->length; (*total_objects)++; LC_RECDES_TO_GET_ONEOBJ (fetch_area, obj, &recdes); if (desc_disk_to_attr_info (thread_p, &obj->oid, &recdes, &attr_info) == NO_ERROR) { object_processed = process_object (thread_p, &upd_scancache, &attr_info, &obj->oid); if (object_processed != 1) { lock_unlock_object (thread_p, &obj->oid, class_oid, oid_lock, true); if (object_processed == -1) { (*failed_objects)++; } } else { (*modified_objects)++; } } else { (*failed_objects)++; } } COPY_OID (&prev_oid, &obj->oid); obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj); } if (fetch_area) { locator_free_copy_area (fetch_area); } } else { /* No more objects */ break; } } else { ret = ER_FAILED; break; } } COPY_OID (last_processed_oid, &last_oid); end: heap_attrinfo_end (thread_p, &attr_info); heap_scancache_end_modify (thread_p, &upd_scancache); return ret; }
/* * xstats_update_class_statistics () - Updates the statistics for the objects * of a given class * return: * class_id(in): Identifier of the class * * Note: It first retrieves the whole catalog information about this class, * including all possible forms of disk representations for the instance * objects. Then, it performs a complete pass on the heap file of the * class, reading in all of the instance objects one by one and * calculating the ranges of numeric attribute values (ie. min. & max. * values for each numeric attribute). * * During this pass on the heap file, these values are maintained * separately for objects with the same representation. Each minimum and * maximum value is initialized when the first instance of the class * with the corresponding representation is encountered. These values are * continually updated as attribute values exceeding the known range are * encountered. At the end of this pass, these individual ranges for * each representation are uniformed in the last (the current) * representation, building the global range values for the attributes * of the class. Then, the btree statistical information is obtained for * each attribute that is indexed and stored in this final representation * structure. Finally, a new timestamp is obtained for these class * statistics and they are stored to disk within the catalog structure * for the last class representation. */ int xstats_update_class_statistics (THREAD_ENTRY * thread_p, OID * class_id_p) { CLS_INFO *cls_info_p = NULL; REPR_ID repr_id; DISK_REPR *disk_repr_p = NULL; DISK_ATTR *disk_attr_p = NULL; BTREE_STATS *btree_stats_p = NULL; HEAP_SCANCACHE hf_scan_cache, *hf_scan_cache_p = NULL; HEAP_CACHE_ATTRINFO hf_cache_attr_info, *hf_cache_attr_info_p = NULL; RECDES recdes; OID oid; SCAN_CODE scan_rc; DB_VALUE *db_value_p; DB_DATA *db_data_p; int i, j; cls_info_p = catalog_get_class_info (thread_p, class_id_p); if (cls_info_p == NULL) { goto error; } /* if class information was not obtained */ if (cls_info_p->hfid.vfid.fileid < 0 || cls_info_p->hfid.vfid.volid < 0) { /* The class does not have a heap file (i.e. it has no instances); so no statistics can be obtained for this class; just set 'tot_objects' field to 0 and return. */ cls_info_p->tot_objects = 0; if (catalog_add_class_info (thread_p, class_id_p, cls_info_p) != NO_ERROR) { goto error; } catalog_free_class_info (cls_info_p); return NO_ERROR; } if (catalog_get_last_representation_id (thread_p, class_id_p, &repr_id) != NO_ERROR) { goto error; } disk_repr_p = catalog_get_representation (thread_p, class_id_p, repr_id); if (disk_repr_p == NULL) { goto error; } cls_info_p->tot_pages = file_get_numpages (thread_p, &cls_info_p->hfid.vfid); cls_info_p->tot_objects = 0; disk_repr_p->num_objects = 0; /* scan whole object of the class and update the statistics */ if (heap_scancache_start (thread_p, &hf_scan_cache, &(cls_info_p->hfid), class_id_p, true, false, LOCKHINT_NONE) != NO_ERROR) { goto error; } hf_scan_cache_p = &hf_scan_cache; if (heap_attrinfo_start (thread_p, class_id_p, -1, NULL, &hf_cache_attr_info) != NO_ERROR) { goto error; } hf_cache_attr_info_p = &hf_cache_attr_info; /* Obtain minimum and maximum value of the instances for each attribute of the class and count the number of objects by scanning heap file */ recdes.area_size = -1; scan_rc = heap_first (thread_p, &(cls_info_p->hfid), class_id_p, &oid, &recdes, hf_scan_cache_p, PEEK); while (scan_rc == S_SUCCESS) { if (heap_attrinfo_read_dbvalues (thread_p, &oid, &recdes, hf_cache_attr_info_p) != NO_ERROR) { scan_rc = S_ERROR; break; } /* Consider attributes only whose type are fixed because min/max value statistics are useful only for those type when calculating the cost of query plan by query optimizer. Variable type attributes, for example VARCHAR(STRING), take constant number of selectivity. */ for (i = 0; i < disk_repr_p->n_fixed; i++) { disk_attr_p = &(disk_repr_p->fixed[i]); db_value_p = heap_attrinfo_access (disk_attr_p->id, hf_cache_attr_info_p); if (db_value_p != NULL && db_value_is_null (db_value_p) != true) { db_data_p = db_value_get_db_data (db_value_p); if (disk_repr_p->num_objects == 0) { /* first object */ disk_attr_p->min_value = *db_data_p; disk_attr_p->max_value = *db_data_p; } else { /* compare with previous values */ if (stats_compare_data (db_data_p, &disk_attr_p->min_value, disk_attr_p->type) < 0) { disk_attr_p->min_value = *db_data_p; } if (stats_compare_data (db_data_p, &disk_attr_p->max_value, disk_attr_p->type) > 0) { disk_attr_p->max_value = *db_data_p; } } } } cls_info_p->tot_objects++; disk_repr_p->num_objects++; scan_rc = heap_next (thread_p, &(cls_info_p->hfid), class_id_p, &oid, &recdes, hf_scan_cache_p, PEEK); } if (scan_rc == S_ERROR) { goto error; } heap_attrinfo_end (thread_p, hf_cache_attr_info_p); if (heap_scancache_end (thread_p, hf_scan_cache_p) != NO_ERROR) { goto error; } /* update the index statistics for each attribute */ for (i = 0; i < disk_repr_p->n_fixed + disk_repr_p->n_variable; i++) { if (i < disk_repr_p->n_fixed) { disk_attr_p = disk_repr_p->fixed + i; } else { disk_attr_p = disk_repr_p->variable + (i - disk_repr_p->n_fixed); } for (j = 0, btree_stats_p = disk_attr_p->bt_stats; j < disk_attr_p->n_btstats; j++, btree_stats_p++) { if (btree_get_stats (thread_p, &btree_stats_p->btid, btree_stats_p, true) != NO_ERROR) { goto error; } } } /* replace the current disk representation structure/information in the catalog with the newly computed statistics */ if (catalog_add_representation (thread_p, class_id_p, repr_id, disk_repr_p) != NO_ERROR) { goto error; } cls_info_p->time_stamp = stats_get_time_stamp (); if (catalog_add_class_info (thread_p, class_id_p, cls_info_p) != NO_ERROR) { goto error; } if (disk_repr_p) { catalog_free_representation (disk_repr_p); } if (cls_info_p) { catalog_free_class_info (cls_info_p); } return NO_ERROR; error: if (hf_cache_attr_info_p) { heap_attrinfo_end (thread_p, hf_cache_attr_info_p); } if (hf_scan_cache_p) { (void) heap_scancache_end (thread_p, hf_scan_cache_p); } if (disk_repr_p) { catalog_free_representation (disk_repr_p); } if (cls_info_p) { catalog_free_class_info (cls_info_p); } return er_errid (); }