File locator.c¶
File List > cubrid > src > transaction > locator.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* locator.c - Transaction object locator (Both client & server)
*/
#ident "$Id$"
#include "locator.h"
#include "config.h"
#include "porting.h"
#include "memory_alloc.h"
#include "oid.h"
#include "object_representation.h"
#include "error_manager.h"
#include "storage_common.h"
#if defined(SERVER_MODE)
#include "connection_error.h"
#endif /* SERVER_MODE */
#include "thread_compat.hpp"
#if defined(SERVER_MODE)
#include "thread_manager.hpp" // for thread_get_thread_entry_info
#endif /* SERVER_MODE */
#include <stdio.h>
#include <string.h>
#include <assert.h>
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
#if !defined(SERVER_MODE)
#define pthread_mutex_init(a, b)
#define pthread_mutex_destroy(a)
#define pthread_mutex_lock(a) 0
#define pthread_mutex_unlock(a)
static int rv;
#endif /* !SERVER_MODE */
#if defined(SERVER_MODE)
#define LOCATOR_NKEEP_LIMIT (200)
#else /* SERVER_MODE */
#define LOCATOR_NKEEP_LIMIT (2)
#endif /* SERVER_MODE */
#define LOCATOR_CACHED_COPYAREA_SIZE_LIMIT \
(IO_MAX_PAGE_SIZE * 2 + sizeof (LC_COPYAREA))
typedef struct locator_global LOCATOR_GLOBAL;
struct locator_global
{
struct locator_global_copyareas
{
int number; /* Num of copy areas that has been kept */
LC_COPYAREA *areas[LOCATOR_NKEEP_LIMIT]; /* Array of free copy areas */
#if defined(SERVER_MODE)
pthread_mutex_t lock;
#endif /* SERVER_MODE */
} copy_areas;
struct locator_global_lockset_areas
{
int number; /* Num of requested areas that has been kept */
LC_LOCKSET *areas[LOCATOR_NKEEP_LIMIT]; /* Array of free lockset areas */
#if defined(SERVER_MODE)
pthread_mutex_t lock;
#endif /* SERVER_MODE */
} lockset_areas;
struct locator_global_lockhint_areas
{
int number; /* Num of lockhinted areas that has been kept */
LC_LOCKHINT *areas[LOCATOR_NKEEP_LIMIT]; /* Array of free lockhinted */
#if defined(SERVER_MODE)
pthread_mutex_t lock;
#endif /* SERVER_MODE */
} lockhint_areas;
struct locator_global_packed_areas
{
int number; /* Num of packed areas that have been kept */
LC_COPYAREA *areas[LOCATOR_NKEEP_LIMIT]; /* Array of free packed areas */
#if defined(SERVER_MODE)
pthread_mutex_t lock;
#endif /* SERVER_MODE */
} packed_areas;
};
static LOCATOR_GLOBAL locator_Keep;
static LC_COPYAREA packed_req_area_ptrs[LOCATOR_NKEEP_LIMIT];
static bool locator_Is_initialized = false;
static char *locator_allocate_packed (int packed_size);
static char *locator_reallocate_packed (char *packed, int packed_size);
#if defined(CUBRID_DEBUG)
static void locator_dump_string (FILE * out_fp, char *dump_string, int length);
static void locator_dump_copy_area_one_object (FILE * out_fp, LC_COPYAREA_ONEOBJ * obj, int obj_index,
const LC_COPYAREA * copyarea, int print_rec);
#endif
static int locator_initialize_lockset (LC_LOCKSET * lockset, int length, int max_reqobjs, LOCK reqobj_inst_lock,
LOCK reqobj_class_lock, int quit_on_errors);
#if defined(CUBRID_DEBUG)
static void locator_dump_lockset_area_info (FILE * out_fp, LC_LOCKSET * lockset);
static void locator_dump_lockset_classes (FILE * out_fp, LC_LOCKSET * lockset);
static void locator_dump_lockset_objects (FILE * out_fp, LC_LOCKSET * lockset);
#endif
static char *locator_pack_lockset_header (char *packed, LC_LOCKSET * lockset);
static char *locator_pack_lockset_classes (char *packed, LC_LOCKSET * lockset);
static char *locator_pack_lockset_objects (char *packed, LC_LOCKSET * lockset);
static char *locator_unpack_lockset_header (char *unpacked, LC_LOCKSET * lockset);
static char *locator_unpack_lockset_classes (char *unpacked, LC_LOCKSET * lockset);
static char *locator_unpack_lockset_objects (char *unpacked, LC_LOCKSET * lockset);
static int locator_initialize_lockhint (LC_LOCKHINT * lockhint, int length, int max_classes, bool quit_on_errors);
#if defined(CUBRID_DEBUG)
static void locator_dump_lockhint_info (FILE * out_fp, LC_LOCKHINT * lockhint);
static void locator_dump_lockhint_classes (FILE * out_fp, LC_LOCKHINT * lockhint);
#endif
static char *locator_pack_lockhint_header (char *packed, LC_LOCKHINT * lockhint);
static char *locator_pack_lockhint_classes (char *packed, LC_LOCKHINT * lockhint);
static char *locator_unpack_lockhint_header (char *unpacked, LC_LOCKHINT * lockhint);
static char *locator_unpack_lockhint_classes (char *unpacked, LC_LOCKHINT * lockhint);
static bool locator_is_hfid_equal (HFID * hfid1_p, HFID * hfid2_p);
/*
* locator_is_hfid_equal:
*
* return: bool
*
* hfid1_p(in):
* hfid2_p(in):
*
* NOTE:
*/
static bool
locator_is_hfid_equal (HFID * hfid1_p, HFID * hfid2_p)
{
return (hfid1_p->vfid.fileid == hfid2_p->vfid.fileid && hfid1_p->vfid.volid == hfid2_p->vfid.volid
&& hfid1_p->hpgid == hfid2_p->hpgid);
}
/*
* locator_initialize_areas: initialize cache areas
*
* return: nothing
*
* NOTE: Initialize all areas.
*/
void
locator_initialize_areas (void)
{
int i;
if (locator_Is_initialized)
{
return;
}
locator_Keep.copy_areas.number = 0;
locator_Keep.lockset_areas.number = 0;
locator_Keep.lockhint_areas.number = 0;
locator_Keep.packed_areas.number = 0;
#if defined(SERVER_MODE)
pthread_mutex_init (&locator_Keep.copy_areas.lock, NULL);
pthread_mutex_init (&locator_Keep.lockset_areas.lock, NULL);
pthread_mutex_init (&locator_Keep.lockhint_areas.lock, NULL);
pthread_mutex_init (&locator_Keep.packed_areas.lock, NULL);
#endif /* SERVER_MODE */
for (i = 0; i < LOCATOR_NKEEP_LIMIT; i++)
{
locator_Keep.copy_areas.areas[i] = NULL;
locator_Keep.lockset_areas.areas[i] = NULL;
locator_Keep.lockhint_areas.areas[i] = NULL;
locator_Keep.packed_areas.areas[i] = &packed_req_area_ptrs[i];
}
locator_Is_initialized = true;
}
/*
* locator_free_areas: Free cached areas
*
* return: nothing
*
* NOTE: Free all areas that has been cached.
*/
void
locator_free_areas (void)
{
int i;
if (locator_Is_initialized == false)
{
return;
}
for (i = 0; i < locator_Keep.copy_areas.number; i++)
{
free_and_init (locator_Keep.copy_areas.areas[i]);
}
for (i = 0; i < locator_Keep.lockset_areas.number; i++)
{
if (locator_Keep.lockset_areas.areas[i]->packed)
{
free_and_init (locator_Keep.lockset_areas.areas[i]->packed);
}
free_and_init (locator_Keep.lockset_areas.areas[i]);
}
for (i = 0; i < locator_Keep.lockhint_areas.number; i++)
{
if (locator_Keep.lockhint_areas.areas[i]->packed)
{
free_and_init (locator_Keep.lockhint_areas.areas[i]->packed);
}
free_and_init (locator_Keep.lockhint_areas.areas[i]);
}
for (i = 0; i < locator_Keep.packed_areas.number; i++)
{
free_and_init (locator_Keep.packed_areas.areas[i]->mem);
}
locator_Keep.copy_areas.number = 0;
locator_Keep.lockset_areas.number = 0;
locator_Keep.lockhint_areas.number = 0;
locator_Keep.packed_areas.number = 0;
#if defined(SERVER_MODE)
pthread_mutex_destroy (&locator_Keep.copy_areas.lock);
pthread_mutex_destroy (&locator_Keep.lockset_areas.lock);
pthread_mutex_destroy (&locator_Keep.lockhint_areas.lock);
pthread_mutex_destroy (&locator_Keep.packed_areas.lock);
#endif /* SERVER_MODE */
locator_Is_initialized = false;
}
/*
*
* FETCH/FLUSH COPY AREA
*
*/
/*
* locator_allocate_packed: allocate an area to pack stuff
*
* return: char * (pack area)
*
* packed_size(in): Packed size needed
*
* NOTE: Allocate an area to pack the stuff such as lockset area
* which is sent over the network. The caller needs to free the
* packed area.
*/
static char *
locator_allocate_packed (int packed_size)
{
char *packed_area = NULL;
int i, tail;
#if defined (SERVER_MODE)
int rv;
#endif /* SERVER_MODE */
rv = pthread_mutex_lock (&locator_Keep.packed_areas.lock);
for (i = 0; i < locator_Keep.packed_areas.number; i++)
{
if (locator_Keep.packed_areas.areas[i]->length >= packed_size)
{
/*
* Make sure that the caller is not assuming that the area is
* initialized to zeros. That is, make sure caller initialize the area
*/
MEM_REGION_SCRAMBLE (locator_Keep.packed_areas.areas[i]->mem, locator_Keep.packed_areas.areas[i]->length);
packed_area = locator_Keep.packed_areas.areas[i]->mem;
packed_size = locator_Keep.packed_areas.areas[i]->length;
locator_Keep.packed_areas.number--;
/* Move the tail to current location */
tail = locator_Keep.packed_areas.number;
locator_Keep.packed_areas.areas[i]->mem = locator_Keep.packed_areas.areas[tail]->mem;
locator_Keep.packed_areas.areas[i]->length = locator_Keep.packed_areas.areas[tail]->length;
break;
}
}
pthread_mutex_unlock (&locator_Keep.packed_areas.lock);
if (packed_area == NULL)
{
packed_area = (char *) malloc (packed_size);
}
return packed_area;
}
/*
* locator_reallocate_packed: Reallocate an area to pack stuff
*
* return: char * (pack area)
*
* packed(in): Packed pointer
* packed_size(in): New size
*
* NOTE: Reallocate the given packed area with given size.
*/
static char *
locator_reallocate_packed (char *packed, int packed_size)
{
return (char *) realloc (packed, packed_size);
}
/*
* locator_free_packed: Free a packed area
*
* return: nothing
*
* packed_area(in): Area to free
* packed_size(in): Size of area to free
*
* NOTE: Free the given packed area
*/
void
locator_free_packed (char *packed_area, int packed_size)
{
int tail;
#if defined (SERVER_MODE)
int rv;
#endif /* SERVER_MODE */
rv = pthread_mutex_lock (&locator_Keep.packed_areas.lock);
if (locator_Keep.packed_areas.number < LOCATOR_NKEEP_LIMIT)
{
tail = locator_Keep.packed_areas.number;
locator_Keep.packed_areas.areas[tail]->mem = packed_area;
locator_Keep.packed_areas.areas[tail]->length = packed_size;
/*
* Scramble the memory, so that the developer detects invalid references
* to free'd areas
*/
MEM_REGION_SCRAMBLE (locator_Keep.packed_areas.areas[tail]->mem, locator_Keep.packed_areas.areas[tail]->length);
locator_Keep.packed_areas.number++;
}
else
{
free_and_init (packed_area);
}
pthread_mutex_unlock (&locator_Keep.packed_areas.lock);
}
#if defined (ENABLE_UNUSED_FUNCTION)
/*
* locator_allocate_copyarea; Allocate a copy area for fetching and flushing
*
* return: LC_COPYAREA *
*
* npages(in): Number of needed pages
*
* NOTE: Allocate a flush/fetch area of the given size.
*/
LC_COPYAREA *
locator_allocate_copyarea (DKNPAGES npages)
{
return locator_allocate_copy_area_by_length (npages * IO_PAGESIZE);
}
#endif
/*
* locator_allocate_copy_area_by_length: Allocate a copy area for
* fetching and flushing purposes.
*
* return: LC_COPYAREA *
*
* min_length(in):Length of the copy area
*
* NOTE: Allocate a flush/fetch area of the given length.
*/
LC_COPYAREA *
locator_allocate_copy_area_by_length (int min_length)
{
LC_COPYAREA *copyarea = NULL;
int network_pagesize;
int i;
#if defined (SERVER_MODE)
int rv;
#endif /* SERVER_MODE */
/*
* Make the min_length to be multiple of NETWORK_PAGESIZE since the
* copyareas are used to copy objects to/from server and we would like to
* maximize the communication line.
*/
network_pagesize = db_network_page_size ();
min_length = DB_ALIGN (min_length, network_pagesize);
/*
* Do we have an area of given or larger length cached ?
*/
rv = pthread_mutex_lock (&locator_Keep.copy_areas.lock);
for (i = 0; i < locator_Keep.copy_areas.number; i++)
{
if (locator_Keep.copy_areas.areas[i]->length >= min_length)
{
copyarea = locator_Keep.copy_areas.areas[i];
locator_Keep.copy_areas.areas[i] = locator_Keep.copy_areas.areas[--locator_Keep.copy_areas.number];
min_length = copyarea->length;
/*
* Make sure that the caller is not assuming that the area is
* initialized to zeros. That is, make sure caller initialize the area
*/
MEM_REGION_SCRAMBLE (copyarea, copyarea->length);
break;
}
}
pthread_mutex_unlock (&locator_Keep.copy_areas.lock);
if (copyarea == NULL)
{
copyarea = (LC_COPYAREA *) malloc (min_length + sizeof (*copyarea));
if (copyarea == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
(size_t) (min_length + sizeof (*copyarea)));
return NULL;
}
}
copyarea->mem = (char *) copyarea + sizeof (*copyarea);
copyarea->length = min_length;
return copyarea;
}
LC_COPYAREA *
locator_reallocate_copy_area_by_length (LC_COPYAREA * old_area, int new_length)
{
LC_COPYAREA_MANYOBJS *old_mobjs, *new_mobjs;
LC_COPYAREA_ONEOBJ *old_obj, *new_obj;
LC_COPYAREA *new_area = NULL;
int i, last_obj_offset = -1;
int last_obj_length = 0;
int old_content_length = 0;
if (old_area == NULL)
{
return NULL;
}
old_mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (old_area);
if (new_length < old_area->length)
{
return NULL;
}
new_area = locator_allocate_copy_area_by_length (new_length);
if (new_area == NULL)
{
return NULL;
}
new_mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (new_area);
new_mobjs->num_objs = old_mobjs->num_objs;
new_mobjs->multi_update_flags = old_mobjs->multi_update_flags;
for (i = 0; i < old_mobjs->num_objs; i++)
{
old_obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (old_mobjs, i);
new_obj = LC_FIND_ONEOBJ_PTR_IN_COPYAREA (new_mobjs, i);
LC_COPY_ONEOBJ (new_obj, old_obj);
if (old_obj->offset > last_obj_offset)
{
last_obj_offset = old_obj->offset;
last_obj_length = old_obj->length;
}
}
if (last_obj_offset != -1)
{
old_content_length = last_obj_offset + last_obj_length;
}
memcpy (new_area->mem, old_area->mem, old_content_length);
locator_free_copy_area (old_area);
return new_area;
}
/*
* locator_free_copy_area: Free a copy area
*
* return:
*
* copyarea(in): Area to free
*
* NOTE: Free the given copy area.
*/
void
locator_free_copy_area (LC_COPYAREA * copyarea)
{
#if defined (SERVER_MODE)
int rv;
#endif /* SERVER_MODE */
if (LOCATOR_CACHED_COPYAREA_SIZE_LIMIT < (size_t) copyarea->length)
{
free_and_init (copyarea);
return;
}
rv = pthread_mutex_lock (&locator_Keep.copy_areas.lock);
if (locator_Keep.copy_areas.number < LOCATOR_NKEEP_LIMIT)
{
/* Scramble the memory, so that the developer detects invalid references to free'd areas */
MEM_REGION_SCRAMBLE (copyarea->mem, copyarea->length);
locator_Keep.copy_areas.areas[locator_Keep.copy_areas.number++] = copyarea;
pthread_mutex_unlock (&locator_Keep.copy_areas.lock);
}
else
{
pthread_mutex_unlock (&locator_Keep.copy_areas.lock);
free_and_init (copyarea);
}
}
/*
* locator_pack_copy_area_descriptor: Pack object descriptors for a copy area
*
* return: updated pack area pointer
*
* num_objs(in): Number of objects
* copyarea(in): Copy area where objects are placed
* desc(in): Packed descriptor array
*
* NOTE: Pack the desc to be sent over the network from the copy area.
* The caller is responsible for determining that desc is large
* enough to hold the packed data.
*/
char *
locator_pack_copy_area_descriptor (int num_objs, LC_COPYAREA * copyarea, char *desc, int desc_len)
{
LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
char *ptr;
int i;
mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (copyarea);
assert (num_objs <= mobjs->num_objs);
ptr = desc;
for (i = 0, obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs); i < num_objs;
i++, obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj))
{
ptr = or_pack_int (ptr, obj->operation);
ptr = or_pack_int (ptr, obj->flag);
ptr = or_pack_hfid (ptr, &obj->hfid);
ptr = or_pack_oid (ptr, &obj->class_oid);
ptr = or_pack_oid (ptr, &obj->oid);
ptr = or_pack_int (ptr, obj->length);
ptr = or_pack_int (ptr, obj->offset);
assert (CAST_BUFLEN (ptr - desc) <= desc_len);
}
return ptr;
}
/*
* locator_unpack_copy_area_descriptor: Unpack object descriptors for a copy area
*
* return: updated pack area pointer
*
* num_objs(in): Number of objects
* copyarea(in): Copy area where objects are placed
* desc(in): Packed descriptor array
*
* NOTE: Unpack the desc sent over the network and place them in the
* copy area. The caller is responsible for determining that
* copyarea is large enough to hold the unpacked data.
*/
char *
locator_unpack_copy_area_descriptor (int num_objs, LC_COPYAREA * copyarea, char *desc, int packed_desc_size)
{
LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
int ope;
int i;
mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (copyarea);
mobjs->num_objs = num_objs;
if (packed_desc_size > 0)
{
obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs);
obj -= num_objs;
obj++;
memcpy (obj, desc, packed_desc_size);
}
else
{
for (i = 0, obj = LC_START_ONEOBJ_PTR_IN_COPYAREA (mobjs); i < num_objs;
i++, obj = LC_NEXT_ONEOBJ_PTR_IN_COPYAREA (obj))
{
desc = or_unpack_int (desc, &ope);
obj->operation = (LC_COPYAREA_OPERATION) ope;
desc = or_unpack_int (desc, &obj->flag);
desc = or_unpack_hfid (desc, &obj->hfid);
desc = or_unpack_oid (desc, &obj->class_oid);
desc = or_unpack_oid (desc, &obj->oid);
desc = or_unpack_int (desc, &obj->length);
desc = or_unpack_int (desc, &obj->offset);
}
}
return desc;
}
/*
* locator_send_copy_area: find the active areas to be sent over the net
*
* return: number of objects in the copy area
*
* copyarea(in):Copy area where objects are placed
* contents_ptr(in):Pointer to content of objects
* (Set as a side effect)
* contents_length(in):Length of content area
* (Set as a side effect)
* desc_ptr(in):Pointer to descriptor pointer array
* (Set as a side effect)
* desc_length(in):Length of descriptor pointer array
* (Set as a side effect)
*
* NOTE: Find the active areas (content and descriptor) to be sent over
* the network.
* The content is sent as is, but the desc are packed.
* The caller needs to free *desc_ptr.
*/
int
locator_send_copy_area (LC_COPYAREA * copyarea, char **contents_ptr, int *contents_length, char **desc_ptr,
int *desc_length, bool encode_endian)
{
LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
int offset = -1;
int i, len;
char *end;
*contents_ptr = copyarea->mem;
mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (copyarea);
*desc_length = DB_ALIGN (LC_AREA_ONEOBJ_PACKED_SIZE, MAX_ALIGNMENT) * mobjs->num_objs;
if (encode_endian)
{
*desc_ptr = (char *) malloc (*desc_length);
if (*desc_ptr == NULL)
{
*desc_length = 0;
return 0;
}
}
/* Find the length of the content area and pack the descriptor area */
if (contents_length != NULL)
{
*contents_length = 0;
if (mobjs->num_objs > 0)
{
obj = &mobjs->objs;
obj++;
for (i = 0; i < mobjs->num_objs; i++)
{
obj--;
if (obj->offset > offset)
{
/* To the right */
*contents_length = obj->length;
offset = obj->offset;
}
}
if (offset != -1)
{
int len = *contents_length;
int aligned_len = DB_ALIGN (len, MAX_ALIGNMENT);
*contents_length = aligned_len + offset; // total len
#if !defined (NDEBUG)
int padded_len = aligned_len - len;
if (padded_len > 0)
{
// make valgrind silent
memset (*contents_ptr + *contents_length - padded_len, 0, padded_len);
}
#endif /* DEBUG */
}
}
}
if (encode_endian)
{
end = locator_pack_copy_area_descriptor (mobjs->num_objs, copyarea, *desc_ptr, *desc_length);
len = CAST_BUFLEN (end - *desc_ptr);
}
else
{
obj = &mobjs->objs;
obj -= mobjs->num_objs;
*desc_ptr = (char *) (obj + 1);
len = CAST_BUFLEN ((char *) &mobjs->objs - (char *) obj);
}
assert (len <= *desc_length);
*desc_length = len;
return mobjs->num_objs;
}
/*
* locator_recv_allocate_copyarea: allocate a copy area for reciving a "copy area"
* from the net.
*
* return: copyarea or NULL(in case of error)
*
* num_objs(in):Number of objects
* packed_desc(in):Pointer to packed descriptor array
* (Set as a side effect)
* packed_desc_length(in):Length of packec descriptor array
* contents_ptr(in):Pointer to content of objects
* (Set as a side effect)
* contents_length(in):Length of content area
*
* NOTE: Prepare a copy area for receiving a "copyarea" of objects
* send by either the client or server.
*/
#if defined(SERVER_MODE)
LC_COPYAREA *
locator_recv_allocate_copyarea (int num_objs, char **contents_ptr, int contents_length)
#else /* SERVER_MODE */
LC_COPYAREA *
locator_recv_allocate_copyarea (int num_objs, char **packed_desc, int packed_desc_length, char **contents_ptr,
int contents_length)
#endif /* SERVER_MODE */
{
LC_COPYAREA *copyarea;
int length;
int desc_length;
if (num_objs > 0)
{
num_objs--;
}
desc_length = (sizeof (LC_COPYAREA_MANYOBJS) + sizeof (LC_COPYAREA_ONEOBJ) * (num_objs));
length = contents_length + desc_length + sizeof (LC_COPYAREA);
copyarea = locator_allocate_copy_area_by_length (length);
if (copyarea == NULL)
{
*contents_ptr = NULL;
}
else
{
*contents_ptr = copyarea->mem;
#if !defined(SERVER_MODE)
*packed_desc = (char *) malloc (packed_desc_length);
if (*packed_desc == NULL)
{
locator_free_copy_area (copyarea);
copyarea = NULL;
*contents_ptr = NULL;
}
#endif /* !SERVER_MODE */
}
return copyarea;
}
#if defined(CUBRID_DEBUG)
/*
* locator_dump_string:
*
* return:
*
* out_fp(in):output file
* dump_string(in):
* length(in):
*
* NOTE:
*/
static void
locator_dump_string (FILE * out_fp, char *dump_string, int length)
{
int i;
for (i = 0; i < length; i++)
{
(void) fputc (dump_string[i], out_fp);
}
}
/*
* locator_dump_copy_area_one_object:
*
* return:
*
* out_fp(in):output file
* obj(in):
* copyarea(in):Copy area where objects are placed
* print_rec(in):true, if records are printed (in ascii format)
*
* NOTE:
*/
static void
locator_dump_copy_area_one_object (FILE * out_fp, LC_COPYAREA_ONEOBJ * obj, int obj_index, const LC_COPYAREA * copyarea,
int print_rec)
{
const char *str_operation;
char *rec;
switch (obj->operation)
{
case LC_FLUSH_INSERT:
case LC_FLUSH_INSERT_PRUNE:
str_operation = "FLUSH_INSERT";
break;
case LC_FLUSH_DELETE:
str_operation = "FLUSH_DELETE";
break;
case LC_FLUSH_UPDATE:
case LC_FLUSH_UPDATE_PRUNE:
str_operation = "FLUSH_UPDATE";
break;
case LC_FETCH:
str_operation = "FETCH";
break;
case LC_FETCH_DELETED:
str_operation = "FETCH_DELETED";
break;
case LC_FETCH_DECACHE_LOCK:
str_operation = "FETCH_DECACHE_LOCK";
break;
case LC_FETCH_VERIFY_CHN:
str_operation = "FETCH_VERIFY_CHN";
break;
default:
str_operation = "UNKNOWN";
break;
}
fprintf (out_fp, "Operation = %s, ", str_operation);
fprintf (out_fp, "Object OID (volid = %d, pageid = %d, slotid = %d)\n", obj->oid.volid, obj->oid.pageid,
obj->oid.slotid);
fprintf (out_fp, " length = %d, offset = %d,\n", obj->length, obj->offset);
fprintf (out_fp, " Heap (volid = %d, fileid = %d, Hdr_pageid = %d)\n", obj->hfid.vfid.volid,
obj->hfid.vfid.fileid, obj->hfid.hpgid);
if (obj->length < 0
&& (obj->length != -1
|| (obj->operation != LC_FLUSH_DELETE && obj->operation != LC_FETCH_DELETED
&& obj->operation != LC_FETCH_DECACHE_LOCK && obj->operation != LC_FETCH_VERIFY_CHN)))
{
fprintf (out_fp, "Bad length = %d for object num = %d, OID = %d|%d|%d\n", obj->length, obj_index, obj->oid.volid,
obj->oid.pageid, obj->oid.slotid);
}
else if (obj->offset > copyarea->length
|| (obj->offset < 0
&& (obj->offset != -1
|| (obj->operation != LC_FLUSH_DELETE && obj->operation != LC_FETCH_DELETED
&& obj->operation != LC_FETCH_DECACHE_LOCK))))
{
fprintf (out_fp, "Bad offset = %d for object num = %d, OID = %d|%d|%d\n", obj->offset, obj_index, obj->oid.volid,
obj->oid.pageid, obj->oid.slotid);
}
else if (print_rec)
{
rec = (char *) copyarea->mem + obj->offset;
locator_dump_string (out_fp, rec, obj->length);
fprintf (out_fp, "\n");
}
}
/*
* locator_dump_copy_area: dump objects placed in copy area
*
* return:
*
* out_fp(in):output file
* copyarea(in):Copy area where objects are placed
* print_rec(in):true, if records are printed (in ascii format)
*
* NOTE: Dump the objects placed in area. The function also detects
* some inconsistencies with the copy area. The actual data of
* the objects is not dumped.
* This function is used for DEBUGGING PURPOSES.
*/
void
locator_dump_copy_area (FILE * out_fp, const LC_COPYAREA * copyarea, int print_rec)
{
LC_COPYAREA_MANYOBJS *mobjs; /* Describe multiple objects in area */
LC_COPYAREA_ONEOBJ *obj; /* Describe on object in area */
int i;
mobjs = LC_MANYOBJS_PTR_IN_COPYAREA (copyarea);
if (mobjs->num_objs != 0)
{
fprintf (out_fp, "\n\n***Dumping fetch/flush area for Num_objs = %d*** \n", mobjs->num_objs);
obj = &mobjs->objs;
obj++;
for (i = 0; i < mobjs->num_objs; i++)
{
obj--;
locator_dump_copy_area_one_object (out_fp, obj, i, copyarea, print_rec);
}
fprintf (out_fp, "\n\n");
}
}
#endif
/*
*
* LOCK FETCH AREAS
*
*/
/*
* locator_allocate_lockset: allocate a lockset area for requesting objects
*
* return:
*
* max_reqobjs(in):Maximum number of requested objects needed
* reqobj_inst_lock(in):The instance lock for the requested objects
* reqobj_class_lock(in):The class lock for the requested classes
* quit_on_errors(in):Flag which indicate wheter to continue in case of
* errors
*
* NOTE: Allocate a flush/fetch area of the given size.
*/
LC_LOCKSET *
locator_allocate_lockset (int max_reqobjs, LOCK reqobj_inst_lock, LOCK reqobj_class_lock, int quit_on_errors)
{
LC_LOCKSET *lockset = NULL; /* Area for requested objects */
int length;
int i;
#if defined (SERVER_MODE)
int rv;
#endif /* SERVER_MODE */
length = (sizeof (*lockset) + (max_reqobjs * (sizeof (*(lockset->classes)) + sizeof (*(lockset->objects)))));
/*
* Do we have an area cached, as big as the one needed ?
*/
rv = pthread_mutex_lock (&locator_Keep.lockset_areas.lock);
for (i = 0; i < locator_Keep.lockset_areas.number; i++)
{
if (locator_Keep.lockset_areas.areas[i]->length >= length)
{
lockset = locator_Keep.lockset_areas.areas[i];
locator_Keep.lockset_areas.areas[i] = locator_Keep.lockset_areas.areas[--locator_Keep.lockset_areas.number];
length = lockset->length;
max_reqobjs =
((lockset->length - sizeof (*lockset)) / (sizeof (*(lockset->classes)) + sizeof (*(lockset->objects))));
/*
* Make sure that the caller is not assuming that the area is
* initialized to zeros. That is, make sure caller initialize the area
*/
MEM_REGION_SCRAMBLE (lockset, length);
break;
}
}
pthread_mutex_unlock (&locator_Keep.lockset_areas.lock);
if (lockset == NULL)
{
lockset = (LC_LOCKSET *) malloc (length);
}
if (lockset == NULL)
{
return NULL;
}
if (locator_initialize_lockset (lockset, length, max_reqobjs, reqobj_inst_lock, reqobj_class_lock, quit_on_errors) !=
NO_ERROR)
{
return NULL;
}
return lockset;
}
/*
* locator_initialize_lockset:
*
* return: error code
*
* lockset(in):
* length(in):
* max_reqobjs(in):Maximum number of requested objects needed
* reqobj_inst_lock(in):The instance lock for the requested objects
* reqobj_class_lock(in):The class lock for the requested classes
* quit_on_errors(in):Flag which indicate wheter to continue in case of
* errors
*
* NOTE:
*/
static int
locator_initialize_lockset (LC_LOCKSET * lockset, int length, int max_reqobjs, LOCK reqobj_inst_lock,
LOCK reqobj_class_lock, int quit_on_errors)
{
if (lockset == NULL || length < SSIZEOF (*lockset))
{
return ER_FAILED;
}
lockset->mem = (char *) lockset;
lockset->length = length;
lockset->first_fetch_lockset_call = true;
lockset->max_reqobjs = max_reqobjs;
lockset->num_reqobjs = 0;
lockset->num_reqobjs_processed = -1;
lockset->last_reqobj_cached = -1;
lockset->reqobj_inst_lock = reqobj_inst_lock;
lockset->reqobj_class_lock = reqobj_class_lock;
lockset->num_classes_of_reqobjs = 0;
lockset->num_classes_of_reqobjs_processed = -1;
lockset->last_classof_reqobjs_cached = -1;
lockset->quit_on_errors = quit_on_errors;
lockset->packed = NULL;
lockset->packed_size = 0;
lockset->classes = ((LC_LOCKSET_CLASSOF *) (lockset->mem + sizeof (*lockset)));
lockset->objects = ((LC_LOCKSET_REQOBJ *) (lockset->classes + max_reqobjs));
return NO_ERROR;
}
#if defined (ENABLE_UNUSED_FUNCTION)
/*
* locator_allocate_lockset_by_length: allocate a lockset area for requesting objects
* (the area is not initialized)
*
* return:
*
* length(in):Length of needed area
*
* NOTE: Allocate a lockset area by its length. The area is not fully
* initialized. It must be initialized by the caller.
*/
LC_LOCKSET *
locator_allocate_lockset_by_length (int length)
{
LC_LOCKSET *lockset;
int max_reqobjs;
max_reqobjs = ((length - sizeof (*lockset)) / (sizeof (*(lockset->classes)) + sizeof (*(lockset->objects))));
return locator_allocate_lockset (max_reqobjs, NULL_LOCK, NULL_LOCK, true);
}
#endif
/*
* locator_reallocate_lockset: reallocate a lockset area for requesting objects
*
* return: new lockset or NULL
*
* lockset(in):The old area.. This should not be NULL.
* max_reqobjs(in):The new size
*
* NOTE: Allocate a flush/fetch area of the given size.
*/
LC_LOCKSET *
locator_reallocate_lockset (LC_LOCKSET * lockset, int max_reqobjs)
{
LC_LOCKSET_REQOBJ *old_reqobjs;
int oldmax_reqobjs;
int length;
length = (sizeof (*lockset) + (max_reqobjs * (sizeof (*(lockset->classes)) + sizeof (*(lockset->objects)))));
if (lockset->length < length)
{
lockset = (LC_LOCKSET *) realloc (lockset, length);
if (lockset == NULL)
{
return NULL;
}
}
/*
* Reset to new areas
*/
oldmax_reqobjs =
((lockset->length - (sizeof (*lockset))) / (sizeof (*(lockset->classes)) + sizeof (*(lockset->objects))));
lockset->mem = (char *) lockset;
lockset->length = length;
lockset->max_reqobjs = max_reqobjs;
lockset->classes = ((LC_LOCKSET_CLASSOF *) (lockset->mem + sizeof (*lockset)));
lockset->objects = ((LC_LOCKSET_REQOBJ *) (lockset->classes + max_reqobjs));
/*
* Need to move the object to the right by the number of positions added
*/
old_reqobjs = ((LC_LOCKSET_REQOBJ *) (lockset->classes + oldmax_reqobjs));
memmove (lockset->objects, old_reqobjs, lockset->num_reqobjs * sizeof (*(lockset->objects)));
return lockset;
}
/*
* locator_free_lockset : free a lockset area
*
* return: nothing
*
* lockset(in):Request area to free
*
* NOTE: Free a lockset area
*/
void
locator_free_lockset (LC_LOCKSET * lockset)
{
#if defined (SERVER_MODE)
int rv;
#endif /* SERVER_MODE */
if (lockset->packed)
{
locator_free_packed (lockset->packed, lockset->packed_size);
lockset->packed = NULL;
lockset->packed_size = 0;
}
rv = pthread_mutex_lock (&locator_Keep.lockset_areas.lock);
if (locator_Keep.lockset_areas.number < LOCATOR_NKEEP_LIMIT)
{
/*
* Scramble the memory, so that the developer detects invalid references
* to free'd areas
*/
MEM_REGION_SCRAMBLE ((char *) lockset + sizeof (*lockset), lockset->length - sizeof (*lockset));
locator_Keep.lockset_areas.areas[locator_Keep.lockset_areas.number++] = lockset;
}
else
{
free_and_init (lockset);
}
pthread_mutex_unlock (&locator_Keep.lockset_areas.lock);
}
#if defined(CUBRID_DEBUG)
/*
* locator_dump_lockset : Dump objects in lockset area
*
* return: nothing
*
* out_fp(in):output file
* lockset(in): The lockset area
*
* NOTE:
*/
static void
locator_dump_lockset_area_info (FILE * out_fp, LC_LOCKSET * lockset)
{
fprintf (out_fp, "Mem = %p, length = %d, num_reqobjs = %d,", (void *) (lockset->mem), lockset->length,
lockset->num_reqobjs);
fprintf (out_fp, "Reqobj_inst_lock = %s, Reqobj_class_lock = %s,\n",
lock_to_lockmode_string (lockset->reqobj_inst_lock), lock_to_lockmode_string (lockset->reqobj_class_lock));
fprintf (out_fp, " num_reqobjs_processed = %d, last_reqobj_cached = %d, \n", lockset->num_reqobjs_processed,
lockset->last_reqobj_cached);
fprintf (out_fp, "num_classes_of_reqobjs = %d, ", lockset->num_classes_of_reqobjs);
fprintf (out_fp, "num_classes_of_reqobjs_processed = %d, ", lockset->num_classes_of_reqobjs_processed);
fprintf (out_fp, "last_classof_reqobj_cached = %d", lockset->last_classof_reqobjs_cached);
fprintf (out_fp, "quit_on_errors = %s, classes = %p, objects = %p\n", (lockset->quit_on_errors ? "TRUE" : "FALSE"),
(void *) (lockset->classes), (void *) (lockset->objects));
}
/*
* locator_dump_lockset_classes :
*
* return: nothing
*
* out_fp(in):output file
* lockset(in): The lockset area
*
* NOTE:
*/
static void
locator_dump_lockset_classes (FILE * out_fp, LC_LOCKSET * lockset)
{
int i;
for (i = 0; i < lockset->num_classes_of_reqobjs; i++)
{
fprintf (out_fp, "class_oid = %d|%d|%d, chn = %d\n", lockset->classes[i].oid.volid,
lockset->classes[i].oid.pageid, lockset->classes[i].oid.slotid, lockset->classes[i].chn);
}
}
/*
* locator_dump_lockset_objects :
*
* return: nothing
*
* out_fp(in):output file
* lockset(in): The lockset area
*
* NOTE:
*/
static void
locator_dump_lockset_objects (FILE * out_fp, LC_LOCKSET * lockset)
{
int i;
for (i = 0; i < lockset->num_reqobjs; i++)
{
fprintf (out_fp, "object_oid = %d|%d|%d, chn = %d, class_index = %d\n", lockset->objects[i].oid.volid,
lockset->objects[i].oid.pageid, lockset->objects[i].oid.slotid, lockset->objects[i].chn,
lockset->objects[i].class_index);
}
}
/*
* locator_dump_lockset : Dump objects in lockset area
*
* return: nothing
*
* out_fp(in):output file
* lockset(in): The lockset area
*
* NOTE: Dump the lockset area.
*/
void
locator_dump_lockset (FILE * out_fp, LC_LOCKSET * lockset)
{
int i;
i = (sizeof (*lockset) + (lockset->num_reqobjs * (sizeof (*lockset->classes) + sizeof (*lockset->objects))));
if (lockset->length < i || lockset->classes != ((LC_LOCKSET_CLASSOF *) (lockset->mem + sizeof (*lockset)))
|| lockset->objects < ((LC_LOCKSET_REQOBJ *) (lockset->classes + lockset->num_reqobjs)))
{
fprintf (out_fp, "Area is inconsistent: either area is too small %d", lockset->length);
fprintf (out_fp, " (expect at least %d),\n", i);
fprintf (out_fp, " pointer to classes %p (expected %p), or\n", (void *) (lockset->classes),
(void *) (lockset->mem + sizeof (*lockset)));
fprintf (out_fp, " pointer to objects %p (expected >= %p) are incorrect\n", (void *) (lockset->objects),
(void *) (lockset->classes + lockset->num_reqobjs));
return;
}
fprintf (out_fp, "\n***Dumping lockset area***\n");
locator_dump_lockset_area_info (out_fp, lockset);
locator_dump_lockset_classes (out_fp, lockset);
locator_dump_lockset_objects (out_fp, lockset);
}
#endif
/*
* locator_allocate_and_unpack_lockset: allocate a lockset area and unpack the given
* area onto it
*
* return: lockset area
*
* unpacked(in):Area to unpack
* unpacked_size(in):Size of unpacked area
* unpack_classes(in):whether to unpack classes
* unpack_objects(in):whether to unpack objects
* reg_unpacked(in):Whether the unpacked area is register as part of
* lockset area
*
* NOTE: Allocate a lockset. Then unpack the given area onto it.
*/
LC_LOCKSET *
locator_allocate_and_unpack_lockset (char *unpacked, int unpacked_size, bool unpack_classes, bool unpack_objects,
bool reg_unpacked)
{
char *ptr;
LC_LOCKSET *lockset;
int max_reqobjs;
ptr = unpacked;
ptr = or_unpack_int (ptr, &max_reqobjs); /* Really first call */
ptr = or_unpack_int (ptr, &max_reqobjs);
lockset = locator_allocate_lockset (max_reqobjs, NULL_LOCK, NULL_LOCK, true);
if (lockset == NULL)
{
return NULL;
}
lockset->packed = unpacked;
lockset->packed_size = unpacked_size;
(void) locator_unpack_lockset (lockset, unpack_classes, unpack_objects);
if (reg_unpacked == false)
{
lockset->packed = NULL;
lockset->packed_size = 0;
}
return lockset;
}
/*
* locator_pack_lockset_header : Pack the lockset area header
*
* return:
*
* packed(in):
* lockset(in/out):Lockfetch area to pack
*
* NOTE: that we do not pack several fileds such as: last_reqobj_cached,
* las_classof_reqobjs_cached.
*/
static char *
locator_pack_lockset_header (char *packed, LC_LOCKSET * lockset)
{
packed = or_pack_int (packed, lockset->first_fetch_lockset_call ? 1 : 0);
packed = or_pack_int (packed, lockset->max_reqobjs);
packed = or_pack_int (packed, lockset->num_reqobjs);
packed = or_pack_int (packed, lockset->num_reqobjs_processed);
packed = or_pack_int (packed, (int) lockset->reqobj_inst_lock);
packed = or_pack_int (packed, (int) lockset->reqobj_class_lock);
packed = or_pack_int (packed, lockset->num_classes_of_reqobjs);
packed = or_pack_int (packed, lockset->num_classes_of_reqobjs_processed);
packed = or_pack_int (packed, lockset->quit_on_errors);
return packed;
}
/*
* locator_pack_lockset_classes : Pack the lockset area classes
*
* return:
*
* packed(in):
* lockset(in/out):Lockfetch area to pack
*
* NOTE:
*/
static char *
locator_pack_lockset_classes (char *packed, LC_LOCKSET * lockset)
{
LC_LOCKSET_CLASSOF *class_lockset;
int i;
for (i = 0, class_lockset = lockset->classes; i < lockset->num_classes_of_reqobjs; i++, class_lockset++)
{
packed = or_pack_oid (packed, &class_lockset->oid);
packed = or_pack_int (packed, class_lockset->chn);
}
return packed;
}
/*
* locator_pack_lockset_objects : Pack the lockset area objects
*
* return:
*
* packed(in):
* lockset(in/out):Lockfetch area to pack
*
* NOTE:
*/
static char *
locator_pack_lockset_objects (char *packed, LC_LOCKSET * lockset)
{
LC_LOCKSET_REQOBJ *object;
int i;
for (i = 0, object = lockset->objects; i < lockset->num_reqobjs; i++, object++)
{
packed = or_pack_oid (packed, &object->oid);
packed = or_pack_int (packed, object->chn);
packed = or_pack_int (packed, object->class_index);
}
return packed;
}
/*
* locator_pack_lockset : Pack the lockset area
*
* return: number of bytes that were packed
* lockset packed fileds are set as a side effect,
*
* lockset(in/out):Lockfetch area to pack
* pack_classes(in):whether to pack classes
* pack_objects(in):whether to pack objects
*
* NOTE: Allocate an area to pack the lockset area to be sent over the
* network. The address and size of the packed area is left on
* the lockset area as a side effect. If there was an area
* already present, it is used.
* Then, the lockset area is packed onto this area, the amount of
* packing is returned.
*/
int
locator_pack_lockset (LC_LOCKSET * lockset, bool pack_classes, bool pack_objects)
{
char *packed;
int packed_size;
packed_size = LC_LOCKSET_PACKED_SIZE (lockset);
/*
* Do we have space for packing ?
*/
if (lockset->packed != NULL)
{
/*
* Reuse the current area
*/
if (packed_size > lockset->packed_size)
{
/*
* We need to realloc this area
*/
packed = locator_reallocate_packed (lockset->packed, packed_size);
if (packed == NULL)
{
return 0;
}
lockset->packed = packed;
lockset->packed_size = packed_size;
}
packed = lockset->packed;
}
else
{
packed = locator_allocate_packed (packed_size);
if (packed == NULL)
{
return 0;
}
lockset->packed = packed;
lockset->packed_size = packed_size;
}
packed = locator_pack_lockset_header (packed, lockset);
/*
* Pack the classes of requested objects
*/
if (pack_classes)
{
packed = locator_pack_lockset_classes (packed, lockset);
}
/*
* Pack the requested objects
*/
if (pack_objects)
{
packed = locator_pack_lockset_objects (packed, lockset);
}
return CAST_BUFLEN (packed - lockset->packed);
}
/*
* locator_pack_lockset_header : Pack the lockset area header
*
* return:
*
* packed(in):
* lockset(in/out):Lockfetch area to pack
*
* NOTE: that we do not pack several fileds such as: last_reqobj_cached,
* las_classof_reqobjs_cached.
*/
static char *
locator_unpack_lockset_header (char *unpacked, LC_LOCKSET * lockset)
{
int first_fetch;
unpacked = or_unpack_int (unpacked, &first_fetch);
lockset->first_fetch_lockset_call = (first_fetch == 1) ? true : false;
unpacked = or_unpack_int (unpacked, &lockset->max_reqobjs);
unpacked = or_unpack_int (unpacked, &lockset->num_reqobjs);
unpacked = or_unpack_int (unpacked, &lockset->num_reqobjs_processed);
unpacked = or_unpack_int (unpacked, (int *) &lockset->reqobj_inst_lock);
unpacked = or_unpack_int (unpacked, (int *) &lockset->reqobj_class_lock);
unpacked = or_unpack_int (unpacked, &lockset->num_classes_of_reqobjs);
unpacked = or_unpack_int (unpacked, &lockset->num_classes_of_reqobjs_processed);
unpacked = or_unpack_int (unpacked, &lockset->quit_on_errors);
return unpacked;
}
/*
* locator_pack_lockset_classes : Pack the lockset area classes
*
* return:
*
* packed(in):
* lockset(in/out):Lockfetch area to pack
*
* NOTE:
*/
static char *
locator_unpack_lockset_classes (char *unpacked, LC_LOCKSET * lockset)
{
LC_LOCKSET_CLASSOF *class_lockset;
int i;
for (i = 0, class_lockset = lockset->classes; i < lockset->num_classes_of_reqobjs; i++, class_lockset++)
{
unpacked = or_unpack_oid (unpacked, &class_lockset->oid);
unpacked = or_unpack_int (unpacked, &class_lockset->chn);
}
return unpacked;
}
/*
* locator_pack_lockset_objects : Pack the lockset area objects
*
* return:
*
* packed(in):
* lockset(in/out):Lockfetch area to pack
*
* NOTE:
*/
static char *
locator_unpack_lockset_objects (char *unpacked, LC_LOCKSET * lockset)
{
LC_LOCKSET_REQOBJ *object;
int i;
for (i = 0, object = lockset->objects; i < lockset->num_reqobjs; i++, object++)
{
unpacked = or_unpack_oid (unpacked, &object->oid);
unpacked = or_unpack_int (unpacked, &object->chn);
unpacked = or_unpack_int (unpacked, &object->class_index);
}
return unpacked;
}
/*
* locator_unpack_lockset : unpack a lockset area
*
* return: number of bytes that were unpacked
*
* lockset(in/out):Request area (set as a side effect)
* unpack_classes(in):whether to unpack classes
* unpack_objects(in):whether to unpack objects
*
* NOTE: Unpack the lockset area which was sent over the network.
*/
int
locator_unpack_lockset (LC_LOCKSET * lockset, bool unpack_classes, bool unpack_objects)
{
char *unpacked;
unpacked = lockset->packed;
unpacked = locator_unpack_lockset_header (unpacked, lockset);
/*
* Unpack the classes of requested objects
*/
if (unpack_classes)
{
unpacked = locator_unpack_lockset_classes (unpacked, lockset);
}
/*
* Unpack the requested objects
*/
if (unpack_objects)
{
unpacked = locator_unpack_lockset_objects (unpacked, lockset);
}
return CAST_BUFLEN (unpacked - lockset->packed);
}
/*
* locator_allocate_lockhint : allocate a lockhint area for prelocking and prefetching
* classes during parsing
*
* return: LC_LOCKHINT * or NULL
*
* max_classes(in):Maximum number of classes
* quit_on_errors(in):Flag which indicate wheter to continue in case of
* errors
*
* NOTE: Allocate a lockhint areas.
*/
LC_LOCKHINT *
locator_allocate_lockhint (int max_classes, bool quit_on_errors)
{
LC_LOCKHINT *lockhint = NULL;
int length;
int i;
#if defined (SERVER_MODE)
int rv;
#endif /* SERVER_MODE */
length = sizeof (*lockhint) + (max_classes * sizeof (*(lockhint->classes)));
/* Do we have a lockhint area cached ? */
rv = pthread_mutex_lock (&locator_Keep.lockhint_areas.lock);
for (i = 0; i < locator_Keep.lockhint_areas.number; i++)
{
if (locator_Keep.lockhint_areas.areas[i]->length >= length)
{
lockhint = locator_Keep.lockhint_areas.areas[i];
locator_Keep.lockhint_areas.areas[i] =
locator_Keep.lockhint_areas.areas[--locator_Keep.lockhint_areas.number];
length = lockhint->length;
max_classes = ((lockhint->length - sizeof (*lockhint)) / sizeof (*(lockhint->classes)));
/*
* Make sure that the caller is not assuming that the area is
* initialized to zeros. That is, make sure caller initialize the area
*/
MEM_REGION_SCRAMBLE (lockhint, length);
break;
}
}
pthread_mutex_unlock (&locator_Keep.lockhint_areas.lock);
if (lockhint == NULL)
{
lockhint = (LC_LOCKHINT *) malloc (length);
}
if (lockhint == NULL)
{
return NULL;
}
if (locator_initialize_lockhint (lockhint, length, max_classes, quit_on_errors) != NO_ERROR)
{
return NULL;
}
return lockhint;
}
/*
* locator_initialize_lockhint:
*
* return: error code
*
* lockhint(in):
* length(in):
* max_classes(in):Maximum number of classes
* quit_on_errors(in):Flag which indicate wheter to continue in case of
* errors
*
* NOTE:
*/
static int
locator_initialize_lockhint (LC_LOCKHINT * lockhint, int length, int max_classes, bool quit_on_errors)
{
if (lockhint == NULL || length < SSIZEOF (*lockhint))
{
return ER_FAILED;
}
lockhint->mem = (char *) lockhint;
lockhint->length = length;
lockhint->first_fetch_lockhint_call = true;
lockhint->max_classes = max_classes;
lockhint->num_classes = 0;
lockhint->num_classes_processed = -1;
lockhint->quit_on_errors = quit_on_errors;
lockhint->packed = NULL;
lockhint->packed_size = 0;
lockhint->classes = ((struct lc_lockhint_class *) (lockhint->mem + sizeof (*lockhint)));
return NO_ERROR;
}
/*
* locator_reallocate_lockhint: reallocate a lockhint area for prelocking and
* prefetching classes during parsing
*
* return: LC_LOCKHINT * or NULL
*
* lockhint(in):The old lockhint area.. This should not be NULL
* max_classes(in):The maximum number of classes
*
* NOTE: Reallocate a lockhint areas for lockhinting and prefetching
* purposes during parsing.
*/
LC_LOCKHINT *
locator_reallocate_lockhint (LC_LOCKHINT * lockhint, int max_classes)
{
int length;
length = sizeof (*lockhint) + (max_classes * sizeof (*(lockhint->classes)));
if (lockhint->length < length)
{
lockhint = (LC_LOCKHINT *) realloc (lockhint, length);
if (lockhint == NULL)
{
return NULL;
}
/* Reset to new areas */
lockhint->mem = (char *) lockhint;
lockhint->length = length;
lockhint->max_classes = max_classes;
lockhint->classes = ((struct lc_lockhint_class *) (lockhint->mem + sizeof (*lockhint)));
}
return lockhint;
}
/*
* locator_free_lockhint : free a lockhint area
*
* return: nothing
*
* lockhint(in):Hintlock area to free
*
* NOTE: Free a lockhint area
*/
void
locator_free_lockhint (LC_LOCKHINT * lockhint)
{
#if defined (SERVER_MODE)
int rv;
#endif /* SERVER_MODE */
if (lockhint->packed)
{
locator_free_packed (lockhint->packed, lockhint->packed_size);
lockhint->packed = NULL;
lockhint->packed_size = 0;
}
rv = pthread_mutex_lock (&locator_Keep.lockhint_areas.lock);
if (locator_Keep.lockhint_areas.number < LOCATOR_NKEEP_LIMIT)
{
/*
* Scramble the memory, so that the developer detects invalid references
* to free'd areas
*/
MEM_REGION_SCRAMBLE ((char *) lockhint + sizeof (*lockhint), lockhint->length - sizeof (*lockhint));
locator_Keep.lockhint_areas.areas[locator_Keep.lockhint_areas.number++] = lockhint;
}
else
{
free_and_init (lockhint);
}
pthread_mutex_unlock (&locator_Keep.lockhint_areas.lock);
}
#if defined(CUBRID_DEBUG)
/*
* locator_dump_lockhint_info :
*
* return: nothing
*
* out_fp(in): output file
* lockhint(in):Hintlock area to dump
*
* NOTE:
*/
static void
locator_dump_lockhint_info (FILE * out_fp, LC_LOCKHINT * lockhint)
{
fprintf (out_fp, "Mem = %p, len = %d, max_classes = %d, num_classes = %d\n", (void *) (lockhint->mem),
lockhint->length, lockhint->max_classes, lockhint->num_classes);
fprintf (out_fp, " num_classes_processed = %d,\n", lockhint->num_classes_processed);
}
/*
* locator_dump_lockhint_classes :
*
* return: nothing
*
* out_fp(in): output file
* lockhint(in):Hintlock area to dump
*
* NOTE:
*/
static void
locator_dump_lockhint_classes (FILE * out_fp, LC_LOCKHINT * lockhint)
{
int i;
for (i = 0; i < lockhint->num_classes; i++)
{
fprintf (out_fp, "class_oid = %d|%d|%d, chn = %d, lock = %s, subclasses = %d\n", lockhint->classes[i].oid.volid,
lockhint->classes[i].oid.pageid, lockhint->classes[i].oid.slotid, lockhint->classes[i].chn,
lock_to_lockmode_string (lockhint->classes[i].lock), lockhint->classes[i].need_subclasses);
}
}
/*
* locator_dump_lockhint : dump a lockhint area
*
* return: nothing
*
* out_fp(in): output file
* lockhint(in):Hintlock area to dump
*
* NOTE: Dump the information placed in lockhint area.
* This function is used for DEBUGGING PURPOSES.
*/
void
locator_dump_lockhint (FILE * out_fp, LC_LOCKHINT * lockhint)
{
fprintf (out_fp, "\n***Dumping lockhint area***\n");
locator_dump_lockhint_info (out_fp, lockhint);
locator_dump_lockhint_classes (out_fp, lockhint);
}
#endif
/*
* locator_allocate_and_unpack_lockhint : allocate a lockhint area and unpack the given
* area onto it
*
* return: LC_LOCKHINT * or NULL
*
* unpacked(in):Area to unpack
* unpacked_size(in):Size of unpacked area
* unpack_classes(in):whether to unpack classes
* reg_unpacked(in):Whether the unpacked area is register as part of
* lockhint area
*
* NOTE: Allocate a lockhint area. Then unpack the given area onto it.
*/
LC_LOCKHINT *
locator_allocate_and_unpack_lockhint (char *unpacked, int unpacked_size, bool unpack_classes, bool reg_unpacked)
{
int max_classes;
char *ptr;
LC_LOCKHINT *lockhint = NULL;
ptr = unpacked;
ptr = or_unpack_int (ptr, &max_classes);
lockhint = locator_allocate_lockhint (max_classes, true);
if (lockhint == NULL)
{
return NULL;
}
lockhint->packed = unpacked;
lockhint->packed_size = unpacked_size;
(void) locator_unpack_lockhint (lockhint, unpack_classes);
if (reg_unpacked == false)
{
lockhint->packed = NULL;
lockhint->packed_size = 0;
}
return lockhint;
}
/*
* locator_pack_lockhint_header :
*
* return:
*
* packed(in):
* lockhint(in/out):Hintlock area to pack
*
* NOTE:
*/
static char *
locator_pack_lockhint_header (char *packed, LC_LOCKHINT * lockhint)
{
packed = or_pack_int (packed, lockhint->max_classes);
packed = or_pack_int (packed, lockhint->num_classes);
packed = or_pack_int (packed, lockhint->num_classes_processed);
packed = or_pack_int (packed, lockhint->quit_on_errors);
return packed;
}
/*
* locator_pack_lockhint_classes :
*
* return:
*
* packed(in):
* lockhint(in/out):Hintlock area to pack
*
* NOTE:
*/
static char *
locator_pack_lockhint_classes (char *packed, LC_LOCKHINT * lockhint)
{
LC_LOCKHINT_CLASS *class_lockhint;
int i;
for (i = 0, class_lockhint = lockhint->classes; i < lockhint->num_classes; i++, class_lockhint++)
{
packed = or_pack_oid (packed, &class_lockhint->oid);
packed = or_pack_int (packed, class_lockhint->chn);
packed = or_pack_lock (packed, class_lockhint->lock);
packed = or_pack_int (packed, class_lockhint->need_subclasses);
}
return packed;
}
/*
* locator_pack_lockhint : pack to lockhint area
*
* return: number of bytes that were packed
* lockhint packed fileds are set as a side effect.
*
* lockhint(in/out):Hintlock area to pack
* pack_classes(in):whether to pack classes
*
* NOTE: Allocate an area to pack the lockhint area to be sent over
* the network. The address and size of the packed area is left
* on the lockhint area as a side effect. If there was an area
* already present, it is used.
* Then, the lockhint area is packed onto this area, the amount
* of packing is returned.
*/
int
locator_pack_lockhint (LC_LOCKHINT * lockhint, bool pack_classes)
{
char *packed;
int packed_size;
packed_size = LC_LOCKHINT_PACKED_SIZE (lockhint);
/*
* Do we have space for packing ?
*/
if (lockhint->packed != NULL)
{
/*
* Reuse the current area
*/
if (packed_size > lockhint->packed_size)
{
/*
* We need to realloc this area
*/
packed = locator_reallocate_packed (lockhint->packed, packed_size);
if (packed == NULL)
{
return 0;
}
lockhint->packed = packed;
lockhint->packed_size = packed_size;
}
packed = lockhint->packed;
}
else
{
packed = locator_allocate_packed (packed_size);
if (packed == NULL)
{
return 0;
}
lockhint->packed = packed;
lockhint->packed_size = packed_size;
}
packed = locator_pack_lockhint_header (packed, lockhint);
if (pack_classes)
{
packed = locator_pack_lockhint_classes (packed, lockhint);
}
return CAST_BUFLEN (packed - lockhint->packed);
}
/*
* locator_unpack_lockhint_header :
*
* return:
*
* unpacked(in):
* lockhint(in/out):Hintlock area to pack
*
* NOTE:
*/
static char *
locator_unpack_lockhint_header (char *unpacked, LC_LOCKHINT * lockhint)
{
unpacked = or_unpack_int (unpacked, &lockhint->max_classes);
unpacked = or_unpack_int (unpacked, &lockhint->num_classes);
unpacked = or_unpack_int (unpacked, &lockhint->num_classes_processed);
unpacked = or_unpack_int (unpacked, &lockhint->quit_on_errors);
return unpacked;
}
/*
* locator_unpack_lockhint_classes :
*
* return:
*
* packed(in):
* lockhint(in/out):Hintlock area to pack
*
* NOTE:
*/
static char *
locator_unpack_lockhint_classes (char *unpacked, LC_LOCKHINT * lockhint)
{
LC_LOCKHINT_CLASS *class_lockhint;
int i;
for (i = 0, class_lockhint = lockhint->classes; i < lockhint->num_classes; i++, class_lockhint++)
{
unpacked = or_unpack_oid (unpacked, &class_lockhint->oid);
unpacked = or_unpack_int (unpacked, &class_lockhint->chn);
unpacked = or_unpack_lock (unpacked, &class_lockhint->lock);
unpacked = or_unpack_int (unpacked, &class_lockhint->need_subclasses);
}
return unpacked;
}
/*
* locator_unpack_lockhint : unpack a lockhint area
*
* return: number of bytes that were unpacked
*
* lockhint(in/out):Hintlock area to unpack (set as a side effect)
* unpack_classes(in):whether to unpack classes
*
* NOTE: Unpack the lockhint area which was sent over the network.
*/
int
locator_unpack_lockhint (LC_LOCKHINT * lockhint, bool unpack_classes)
{
char *unpacked;
unpacked = lockhint->packed;
unpacked = locator_unpack_lockhint_header (unpacked, lockhint);
if (unpack_classes)
{
unpacked = locator_unpack_lockhint_classes (unpacked, lockhint);
}
return CAST_BUFLEN (unpacked - lockhint->packed);
}
/*
*
* LC_OIDSET PACKING
*
*/
/*
* locator_make_oid_set () -
*
* return: new oidset structure
*
* NOTE:
* This creates a root LC_OIDSET structure, intended for incremental
* population using locator_add_oid_set.
* Free it with locator_free_oid_set when you're done.
*/
LC_OIDSET *
locator_make_oid_set (void)
{
LC_OIDSET *set;
set = (LC_OIDSET *) db_private_alloc (NULL, sizeof (LC_OIDSET));
if (set == NULL)
{
return NULL;
}
set->total_oids = 0;
set->num_classes = 0;
set->classes = NULL;
set->is_list = true;
return set;
}
/*
* locator_clear_oid_set () -
*
* return: nothing
*
* oidset(in):oidset to clear
*
* NOTE:
* Frees the entries inside an LC_OIDSET but leaves the outer structure
* in place. This could be used in places where we build up a partial
* oidset, flush it, and then fill it up again.
* This is a little complicated as there are two different styles for
* allocation. During incremental LC_OIDSET construction, we'll use
* a linked list but the server will unpack it using arrays. This
* style is maintained in an internal is_list flag in the appropriate
* places.
* This saves having to mess with growing arrays.
*/
void
locator_clear_oid_set (THREAD_ENTRY * thread_p, LC_OIDSET * oidset)
{
LC_CLASS_OIDSET *class_oidset, *c_next;
LC_OIDMAP *oid, *o_next;
if (oidset != NULL)
{
/* map over the classes */
if (oidset->classes != NULL)
{
#if defined (SERVER_MODE)
if (thread_p == NULL)
{
thread_p = thread_get_thread_entry_info ();
}
#endif // SERVER_MODE
for (class_oidset = oidset->classes, c_next = NULL; class_oidset != NULL; class_oidset = c_next)
{
c_next = class_oidset->next;
/* on the client, its important that we NULL out these pointers in case they happen to point to MOPs, we
* don't want to leave GC roots lying around. */
for (oid = class_oidset->oids; oid != NULL; oid = oid->next)
{
oid->mop = NULL;
oid->client_data = NULL;
}
/* free either the list or array of OID map elements */
if (!class_oidset->is_list)
{
db_private_free_and_init (thread_p, class_oidset->oids);
}
else
{
for (oid = class_oidset->oids, o_next = NULL; oid != NULL; oid = o_next)
{
o_next = oid->next;
db_private_free_and_init (thread_p, oid);
}
}
/* if we have a list of classes, free them as we go */
if (oidset->is_list)
{
db_private_free_and_init (thread_p, class_oidset);
}
}
/* if we have an array of classes, free it at the end */
if (!oidset->is_list)
{
db_private_free_and_init (thread_p, oidset->classes);
}
}
oidset->total_oids = 0;
oidset->num_classes = 0;
oidset->classes = NULL;
oidset->is_list = true;
}
}
/*
* locator_free_oid_set () -
*
* return: nothing
*
* oidset(in):oidset to free
*
* NOTE:
* Frees memory associated with an LC_OIDSET.
*/
void
locator_free_oid_set (THREAD_ENTRY * thread_p, LC_OIDSET * oidset)
{
if (oidset != NULL)
{
locator_clear_oid_set (thread_p, oidset);
db_private_free_and_init (thread_p, oidset);
}
}
/*
* locator_add_oid_set () -
*
* return: LC_OIDMAP* or NULL
*
* set(in):oidset to extend
* heap(in):class heap id
* class_oid(in):class OID
* obj_oid(in):the currently temporary object OID
*
* NOTE:
* Adds another temporary OID entry to an LC_OIDSET and returns
* the internal LC_OIDMAP structure associated with that OID.
* NULL is returned on error.
*
* This is normally called by the client with a temporary OID, we check
* to make sure that the same temporary OID is not added twice.
*/
LC_OIDMAP *
locator_add_oid_set (THREAD_ENTRY * thread_p, LC_OIDSET * set, HFID * heap, OID * class_oid, OID * obj_oid)
{
LC_CLASS_OIDSET *class_oidset_p;
LC_OIDMAP *oidmap_p;
oidmap_p = NULL;
/* sanity test, can't extend into fixed structures */
if (set == NULL || !set->is_list)
{
/* can't have a temporary OID without a cached class */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
return NULL;
}
/* see if we already have an entry for this class */
for (class_oidset_p = set->classes; class_oidset_p != NULL; class_oidset_p = class_oidset_p->next)
{
/* MOP comparison would be faster but makes the structre more complex */
if (locator_is_hfid_equal (heap, &(class_oidset_p->hfid)))
{
break;
}
}
#if defined (SERVER_MODE)
if (thread_p == NULL)
{
thread_p = thread_get_thread_entry_info ();
}
#endif // SERVER_MODE
if (class_oidset_p == NULL)
{
/* haven't seen this class yet, add a new entry */
class_oidset_p = (LC_CLASS_OIDSET *) db_private_alloc (thread_p, sizeof (LC_CLASS_OIDSET));
if (class_oidset_p == NULL)
{
return NULL;
}
oidmap_p = (LC_OIDMAP *) db_private_alloc (thread_p, sizeof (LC_OIDMAP));
if (oidmap_p == NULL)
{
db_private_free_and_init (thread_p, class_oidset_p);
return NULL;
}
oidmap_p->next = NULL;
oidmap_p->oid = *obj_oid;
oidmap_p->est_size = 0;
oidmap_p->mop = NULL;
oidmap_p->client_data = NULL;
class_oidset_p->class_oid = *class_oid;
class_oidset_p->hfid = *heap;
class_oidset_p->is_list = true;
class_oidset_p->oids = oidmap_p;
class_oidset_p->num_oids = 1;
class_oidset_p->next = set->classes;
set->classes = class_oidset_p;
set->num_classes++;
set->total_oids++;
}
else
{
/* already have a list for this class, add another object if we don't have one already */
for (oidmap_p = class_oidset_p->oids; oidmap_p != NULL; oidmap_p = oidmap_p->next)
{
if (OID_EQ (&oidmap_p->oid, obj_oid))
{
break;
}
}
if (oidmap_p == NULL)
{
/* never seen this particular temp oid, add another entry */
oidmap_p = (LC_OIDMAP *) db_private_alloc (thread_p, sizeof (LC_OIDMAP));
if (oidmap_p == NULL)
{
return NULL;
}
oidmap_p->next = class_oidset_p->oids;
class_oidset_p->oids = oidmap_p;
oidmap_p->oid = *obj_oid;
oidmap_p->est_size = 0;
oidmap_p->mop = NULL;
oidmap_p->client_data = NULL;
class_oidset_p->num_oids++;
set->total_oids++;
}
}
return oidmap_p;
}
/*
* locator_get_packed_oid_set_size () -
*
* return: packed size
*
* oidset(in):oidset to ponder
*
* Note:
* Returns the number of bytes it would take to create the packed
* representation of an LC_OIDSET as would be produced by
* locator_pack_oid_set.
*/
int
locator_get_packed_oid_set_size (LC_OIDSET * oidset)
{
LC_CLASS_OIDSET *class_oidset;
int size, count;
size = OR_INT_SIZE; /* number of classes */
for (class_oidset = oidset->classes, count = 0; class_oidset != NULL; class_oidset = class_oidset->next, count++)
{
size += OR_OID_SIZE;
size += OR_HFID_SIZE;
size += OR_INT_SIZE;
size += class_oidset->num_oids * (OR_OID_SIZE + OR_INT_SIZE);
}
/* sanity check on count, should set an error or something */
if (count != oidset->num_classes)
{
oidset->num_classes = count;
}
return size;
}
/*
* locator_pack_oid_set () -
*
* return: advanced pointer
*
* buffer(in):buffer in which to pack
* oidset(in):oidset to pack
*
* NOTE:
* Packs the flattened representation of an oidset into a buffer.
* The buffer must be of an appropriate size, you should always call
* locator_get_packed_oid_set_size first.
*/
char *
locator_pack_oid_set (char *buffer, LC_OIDSET * oidset)
{
LC_CLASS_OIDSET *class_oidset;
LC_OIDMAP *oid;
buffer = or_pack_int (buffer, oidset->num_classes);
for (class_oidset = oidset->classes; class_oidset != NULL; class_oidset = class_oidset->next)
{
buffer = or_pack_oid (buffer, &class_oidset->class_oid);
buffer = or_pack_hfid (buffer, &class_oidset->hfid);
buffer = or_pack_int (buffer, class_oidset->num_oids);
for (oid = class_oidset->oids; oid != NULL; oid = oid->next)
{
buffer = or_pack_oid (buffer, &oid->oid);
buffer = or_pack_int (buffer, oid->est_size);
}
}
return buffer;
}
/*
* locator_unpack_oid_set () -
*
* return: unpacked oidset
*
* buffer(in):buffer containing packed representation
* use(in):existing oidset structure to unpack into
*
* NOTE:
* This unpacks the packed representation of an oidset and either updates
* an existing structure or creates and returns a new one.
* If an existing structure is supplied, it MUST be of exactly the same
* format as the one used to create the packed representation.
* This is intended for use on the client after it has sent an oidset
* over to the server for the permanent OID's to be assigned. The
* thing we get back will be identical with only changes to the packed
* OIDs so we don't have to waste time allocating a new structure, we
* can just unpack into the existing structure.
*
* If we're on the server side, we won't have a "use" structure so we
* just allocate a new one. Note that the server uses arrays for
* the class & oidmap lists rather than linked lists.
*/
bool
locator_unpack_oid_set_to_exist (char *buffer, LC_OIDSET * use)
{
LC_CLASS_OIDSET *class_oidset;
LC_OIDMAP *oid;
LC_OIDSET *set = NULL;
int c, o;
char *ptr;
ptr = buffer;
if (use == NULL)
{
return false;
}
set = use;
/* unpack into an existing structure, it better be large enough */
ptr = or_unpack_int (ptr, &c);
if (c != set->num_classes)
{
goto use_error;
}
for (class_oidset = set->classes; class_oidset != NULL; class_oidset = class_oidset->next)
{
/* skip these, could check for consistency */
ptr += OR_OID_SIZE;
ptr += OR_HFID_SIZE;
ptr = or_unpack_int (ptr, &o);
if (o != class_oidset->num_oids)
{
goto use_error;
}
for (oid = class_oidset->oids; oid != NULL; oid = oid->next)
{
/* this is what we came for */
ptr = or_unpack_oid (ptr, &oid->oid);
/* can skip this */
ptr += OR_INT_SIZE;
/* note that we must leave mop & client_data fields untouched !! */
}
}
/* success */
return true;
use_error:
/* need something appropriate */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
return false;
}
LC_OIDSET *
locator_unpack_oid_set_to_new (THREAD_ENTRY * thread_p, char *buffer)
{
LC_CLASS_OIDSET *class_oidset;
LC_OIDMAP *oid;
LC_OIDSET *set;
int c, o, total;
char *ptr;
ptr = buffer;
#if defined (SERVER_MODE)
if (thread_p == NULL)
{
thread_p = thread_get_thread_entry_info ();
}
#endif // SERVER_MODE
/* we have to unpack and build a new structure, use arrays */
set = (LC_OIDSET *) db_private_alloc (thread_p, sizeof (LC_OIDSET));
if (set == NULL)
{
goto memory_error;
}
total = 0;
ptr = or_unpack_int (ptr, &set->num_classes);
if (!set->num_classes)
{
set->classes = NULL;
}
else
{
set->classes = (LC_CLASS_OIDSET *) db_private_alloc (thread_p, sizeof (LC_CLASS_OIDSET) * set->num_classes);
if (set->classes == NULL)
{
goto memory_error;
}
set->is_list = false;
/* initialize things so we can cleanup easier */
for (c = 0, class_oidset = set->classes; c < set->num_classes; c++, class_oidset++)
{
if (c == set->num_classes - 1)
{
class_oidset->next = NULL;
}
else
{
class_oidset->next = class_oidset + 1;
}
class_oidset->oids = NULL;
}
/* load the class data */
for (c = 0, class_oidset = set->classes; c < set->num_classes; c++, class_oidset++)
{
ptr = or_unpack_oid (ptr, &class_oidset->class_oid);
ptr = or_unpack_hfid (ptr, &class_oidset->hfid);
ptr = or_unpack_int (ptr, &class_oidset->num_oids);
class_oidset->oids = (LC_OIDMAP *) db_private_alloc (thread_p, sizeof (LC_OIDMAP) * class_oidset->num_oids);
if (class_oidset->oids == NULL)
{
goto memory_error;
}
class_oidset->is_list = false;
/* load the oid data */
for (o = 0, oid = class_oidset->oids; o < class_oidset->num_oids; o++, oid++)
{
if (o == class_oidset->num_oids - 1)
{
oid->next = NULL;
}
else
{
oid->next = oid + 1;
}
ptr = or_unpack_oid (ptr, &oid->oid);
ptr = or_unpack_int (ptr, &oid->est_size);
oid->mop = NULL;
oid->client_data = NULL;
total++;
}
}
set->total_oids = total;
}
/* success */
return set;
memory_error:
locator_free_oid_set (thread_p, set);
return NULL;
}
bool
locator_manyobj_flag_is_set (LC_COPYAREA_MANYOBJS * copyarea, enum MULTI_UPDATE_FLAG muf)
{
return copyarea->multi_update_flags & muf;
}
void
locator_manyobj_flag_remove (LC_COPYAREA_MANYOBJS * copyarea, enum MULTI_UPDATE_FLAG muf)
{
assert (locator_manyobj_flag_is_set (copyarea, muf));
copyarea->multi_update_flags &= (~muf);
}
void
locator_manyobj_flag_set (LC_COPYAREA_MANYOBJS * copyarea, enum MULTI_UPDATE_FLAG muf)
{
copyarea->multi_update_flags |= muf;
}