File unload_object_file.c¶
File List > cubrid > src > executables > unload_object_file.c
Go to the documentation of this file
/*
*
* 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.
*
*/
/*
* unload_object_file.c:
*/
#ident "$Id$"
#if !defined(WINDOWS)
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif
#include "config.h"
#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#if defined(WINDOWS)
#include <io.h>
#else
#include <unistd.h>
#endif
#include <ctype.h>
#include <sys/stat.h>
#include <math.h>
#include "utility.h"
#include "misc_string.h"
#include "memory_alloc.h"
#include "dbtype.h"
#include "object_representation.h"
#include "work_space.h"
#include "class_object.h"
#include "object_primitive.h"
#include "set_object.h"
#include "db.h"
#include "schema_manager.h"
#include "server_interface.h"
#include "load_object.h"
#include "unload_object_file.h"
#include "db_value_printer.hpp"
#include "network_interface_cl.h"
#include "printer.hpp"
#include "message_catalog.h"
#include "string_opfunc.h"
#include "porting.h"
volatile bool error_occurred = false;
int g_io_buffer_size = 4096;
int g_fd_handle = INVALID_FILE_NO;
bool g_multi_thread_mode = false;
UNLD_THR_PARAM *g_thr_param = NULL;
int g_sampling_records = -1;
static void print_set (print_output & output_ctx, DB_SET * set);
static int fprint_special_set (TEXT_OUTPUT * tout, DB_SET * set);
static int bfmt_print (int bfmt, const DB_VALUE * the_db_bit, char *string, int max_size);
static int print_quoted_str (TEXT_OUTPUT * tout, const char *str, int len, int max_token_len);
static int fprint_special_strings (TEXT_OUTPUT * tout, DB_VALUE * value);
static int write_object_file (TEXT_BUFFER_BLK * head);
#if !defined(WINDOWS)
extern S_WAITING_INFO wi_write_file;
#endif
class text_buffer_mgr
{
private:
pthread_mutex_t m_cs_lock;
TEXT_BUFFER_BLK *m_free_list;
int m_max_cnt_free_list;
int m_cnt_free_list;
void quit_text_buffer_mgr ()
{
TEXT_BUFFER_BLK *tp;
pthread_mutex_lock (&m_cs_lock);
while (m_free_list)
{
tp = m_free_list;
m_free_list = tp->next;
if (tp->buffer)
{
free (tp->buffer);
}
free (tp);
m_cnt_free_list--;
}
pthread_mutex_unlock (&m_cs_lock);
}
public:
text_buffer_mgr ()
{
//m_cs_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init (&m_cs_lock, NULL);
m_free_list = NULL;
m_max_cnt_free_list = m_cnt_free_list = 0;
}
~text_buffer_mgr ()
{
quit_text_buffer_mgr ();
(void) pthread_mutex_destroy (&m_cs_lock);
}
bool init_text_buffer_mgr (int count)
{
pthread_mutex_lock (&m_cs_lock);
assert (m_free_list == NULL);
m_max_cnt_free_list = count;
pthread_mutex_unlock (&m_cs_lock);
return true;
}
TEXT_BUFFER_BLK *get_text_buffer (int alloc_sz)
{
TEXT_BUFFER_BLK *tp = NULL;
if (alloc_sz <= g_io_buffer_size)
{
alloc_sz = g_io_buffer_size;
pthread_mutex_lock (&m_cs_lock);
if (m_free_list)
{
tp = m_free_list;
m_free_list = tp->next;
m_cnt_free_list--;
}
pthread_mutex_unlock (&m_cs_lock);
}
if (!tp)
{
tp = (TEXT_BUFFER_BLK *) calloc (sizeof (TEXT_BUFFER_BLK), 1);
if (tp == NULL)
{
assert (false);
return NULL;
}
}
tp->next = NULL;
if (tp->buffer == NULL)
{
tp->buffer = (char *) malloc (alloc_sz + 1);
if (tp->buffer == NULL)
{
assert (false);
free (tp);
return NULL;
}
tp->ptr = tp->buffer;
tp->iosize = alloc_sz;
tp->count = 0;
}
return tp;
}
void release_text_buffer (TEXT_BUFFER_BLK * tp)
{
/* re-init */
tp->ptr = tp->buffer;
tp->count = 0;
if (tp->iosize == g_io_buffer_size)
{
pthread_mutex_lock (&m_cs_lock);
if (m_cnt_free_list < m_max_cnt_free_list)
{
tp->next = m_free_list;
m_free_list = tp;
m_cnt_free_list++;
pthread_mutex_unlock (&m_cs_lock);
return;
}
pthread_mutex_unlock (&m_cs_lock);
}
if (tp->buffer)
{
free (tp->buffer);
}
free (tp);
}
};
class write_block_queue
{
private:
pthread_mutex_t m_cs_lock;
TEXT_BUFFER_BLK **m_q_blk;
int m_q_size;
int m_front;
int m_rear;
public:
write_block_queue ()
{
//m_cs_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init (&m_cs_lock, NULL);
m_q_blk = NULL;
m_q_size = 0;
m_front = m_rear = 0;
}
~write_block_queue ()
{
if (m_q_blk)
{
TEXT_BUFFER_BLK *head, *pt;
assert (m_front == m_rear);
while (m_front != m_rear)
{
++m_front %= m_q_size;
head = m_q_blk[m_front];
m_q_blk[m_front] = NULL;
while (head)
{
pt = head;
head = head->next;
if (pt->buffer)
{
free (pt->buffer);
}
free (pt);
}
}
free (m_q_blk);
}
(void) pthread_mutex_destroy (&m_cs_lock);
}
bool init_queue (int size)
{
assert (m_q_blk == NULL);
m_front = m_rear = 0;
m_q_blk = (TEXT_BUFFER_BLK **) calloc (size, sizeof (TEXT_BUFFER_BLK *));
if (m_q_blk)
{
m_q_size = size;
return true;
}
else
{
m_q_size = 0;
return false;
}
}
bool enqueue (TEXT_BUFFER_BLK * tout)
{
pthread_mutex_lock (&m_cs_lock);
assert (m_q_blk != NULL);
if ((m_rear + 1) % m_q_size == m_front)
{ // full
pthread_mutex_unlock (&m_cs_lock);
return false;
}
++m_rear %= m_q_size;
assert (m_q_blk[m_rear] == NULL);
m_q_blk[m_rear] = tout;
pthread_mutex_unlock (&m_cs_lock);
return true;
}
TEXT_BUFFER_BLK *dequeue ()
{
TEXT_BUFFER_BLK *pt = NULL;
pthread_mutex_lock (&m_cs_lock);
assert (m_q_blk != NULL);
if (m_front == m_rear)
{
; // empty
}
else
{
++m_front %= m_q_size;
pt = m_q_blk[m_front];
m_q_blk[m_front] = NULL;
}
pthread_mutex_unlock (&m_cs_lock);
return pt;
}
};
// define
static class write_block_queue c_write_blk_queue;
static class text_buffer_mgr c_text_buf_mgr;
bool
init_queue_n_list_for_object_file (int q_size, int blk_size)
{
if (c_write_blk_queue.init_queue (q_size))
{
return c_text_buf_mgr.init_text_buffer_mgr (blk_size);
}
return false;
}
static int
get_text_output_mem (TEXT_OUTPUT * tout, int alloc_sz)
{
TEXT_BUFFER_BLK *pt = NULL;
if (alloc_sz > g_io_buffer_size)
{
alloc_sz += g_io_buffer_size;
}
else
{
alloc_sz = g_io_buffer_size;
}
pt = c_text_buf_mgr.get_text_buffer (alloc_sz);
if (pt == NULL)
{
return ER_FAILED;
}
if (tout->head_ptr == NULL)
{
tout->record_cnt = 0;
tout->head_ptr = pt;
}
else
{
tout->tail_ptr->next = pt;
}
tout->tail_ptr = pt;
return NO_ERROR;
}
int
flushing_write_blk_queue ()
{
TEXT_BUFFER_BLK *head;
head = c_write_blk_queue.dequeue ();
if (head == NULL)
{
return 0;
}
while (head)
{
if (write_object_file (head) != NO_ERROR)
{
return -1;
}
head = c_write_blk_queue.dequeue ();
}
return 1;
}
/*
* print_set - Print the contents of a real DB_SET (not a set descriptor).
* return: void
* output_ctx(in): output context
* set(in): set reference
*/
static void
print_set (print_output & output_ctx, DB_SET * set)
{
DB_VALUE element_value;
int len, i;
len = set_size (set);
output_ctx ("{");
for (i = 0; i < len; i++)
{
if (set_get_element (set, i, &element_value) == NO_ERROR)
{
desc_value_print (output_ctx, &element_value);
if (i < len - 1)
{
output_ctx (", ");
}
}
}
output_ctx ("}");
}
/*
* fprint_special_set - Print the contents of a real DB_SET (not a set
* descriptor).
* return: NO_ERROR, if successful, error code otherwise
* tout(in/out): TEXT_OUTPUT structure
* set(in): set reference
*/
static int
fprint_special_set (TEXT_OUTPUT * tout, DB_SET * set)
{
int error = NO_ERROR;
DB_VALUE element_value;
int len, i;
len = set_size (set);
CHECK_PRINT_ERROR (text_print (tout, "{", 1, NULL));
for (i = 0; i < len; i++)
{
if (set_get_element (set, i, &element_value) == NO_ERROR)
{
CHECK_PRINT_ERROR (desc_value_special_fprint (tout, &element_value));
if (i < len - 1)
{
CHECK_PRINT_ERROR (text_print (tout, ",\n ", 2, NULL));
}
}
}
CHECK_PRINT_ERROR (text_print (tout, "}", 1, NULL));
exit_on_end:
return error;
exit_on_error:
CHECK_EXIT_ERROR (error);
goto exit_on_end;
}
/*
* bfmt_print - Change the given string to a representation of the given bit
* string value in the given format.
* return: -1 if max_size too small, 0 if successful
* bfmt(in): format of bit string (binary or hex format)
* the_db_bit(in): input DB_VALUE
* string(out): output buffer
* max_size(in): size of string
* Note:
* max_size specifies the maximum number of chars that can be stored in
* the string (including final '\0' char); if this is not long enough to
* contain the new string, then an error is returned.
*/
#define MAX_DISPLAY_COLUMN 70
#define DBL_MAX_DIGITS ((int)ceil(DBL_MAX_EXP * log10(FLT_RADIX)))
#define BITS_IN_BYTE 8
#define HEX_IN_BYTE 2
#define BITS_IN_HEX 4
#define BYTE_COUNT(bit_cnt) (((bit_cnt)+BITS_IN_BYTE-1)/BITS_IN_BYTE)
#define BYTE_COUNT_HEX(bit_cnt) (((bit_cnt)+BITS_IN_HEX-1)/BITS_IN_HEX)
static int
bfmt_print (int bfmt, const DB_VALUE * the_db_bit, char *string, int max_size)
{
/*
* Description:
*/
int length = 0;
int string_index = 0;
int byte_index;
int bit_index;
const char *bstring;
int error = NO_ERROR;
static char digits[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
/* Get the buffer and the length from the_db_bit */
bstring = db_get_bit (the_db_bit, &length);
switch (bfmt)
{
case 0: /* BIT_STRING_BINARY */
if (length + 1 > max_size)
{
error = -1;
}
else
{
for (byte_index = 0; byte_index < BYTE_COUNT (length); byte_index++)
{
for (bit_index = 7; bit_index >= 0 && string_index < length; bit_index--)
{
*string = digits[((bstring[byte_index] >> bit_index) & 0x1)];
string++;
string_index++;
}
}
*string = '\0';
}
break;
case 1: /* BIT_STRING_HEX */
if (BYTE_COUNT_HEX (length) + 1 > max_size)
{
error = -1;
}
else
{
for (byte_index = 0; byte_index < BYTE_COUNT (length); byte_index++)
{
*string = digits[((bstring[byte_index] >> BITS_IN_HEX) & 0x0f)];
string++;
string_index++;
if (string_index < BYTE_COUNT_HEX (length))
{
*string = digits[((bstring[byte_index] & 0x0f))];
string++;
string_index++;
}
}
*string = '\0';
}
break;
default:
break;
}
return error;
}
static int
flush_quoted_str (TEXT_OUTPUT * tout, const char *st, int tlen)
{
int ret = NO_ERROR;
int capacity = tout->tail_ptr->iosize - tout->tail_ptr->count;
if (capacity <= tlen)
{
memcpy (tout->tail_ptr->ptr, st, capacity);
tout->tail_ptr->ptr += capacity;
tout->tail_ptr->count += capacity;
tlen -= capacity;
assert (tout->tail_ptr->count == tout->tail_ptr->iosize);
ret = get_text_output_mem (tout, tlen);
if ((ret == NO_ERROR) && (tlen > 0))
{
memcpy (tout->tail_ptr->ptr, st + capacity, tlen);
tout->tail_ptr->ptr += tlen;
tout->tail_ptr->count += tlen;
}
}
else
{
memcpy (tout->tail_ptr->ptr, st, tlen);
tout->tail_ptr->ptr += tlen;
tout->tail_ptr->count += tlen;
}
return ret;
}
/*
* print_quoted_str - print quoted string sequences separated by new line to
* TEXT_OUTPUT given
* return: NO_ERROR if successful, error code otherwise
* tout(out): destination buffer
* str(in) : string input
* len(in): length of string
* max_token_len(in): width of string to format
* Note:
* FIXME :: return error in fwrite...
*/
static int
print_quoted_str (TEXT_OUTPUT * tout, const char *str, int len, int max_token_len)
{
int error = NO_ERROR;
const char *end;
int write_len = 0;
const char *st;
if (tout->tail_ptr == NULL)
{
assert (tout->head_ptr == NULL);
CHECK_PRINT_ERROR (get_text_output_mem (tout, len));
}
else if (tout->tail_ptr->iosize <= tout->tail_ptr->count)
{
assert (tout->tail_ptr->iosize == tout->tail_ptr->count);
CHECK_PRINT_ERROR (get_text_output_mem (tout, len));
}
/* opening quote */
tout->tail_ptr->ptr[0] = '\'';
tout->tail_ptr->ptr++;
tout->tail_ptr->count++;
end = str + len;
for (st = str; str < end; str++)
{
if (*str == '\'')
{
if ((error = flush_quoted_str (tout, st, (int) (str - st))) != NO_ERROR)
{
goto exit_on_error;
}
if ((error = flush_quoted_str (tout, "''", 2)) != NO_ERROR)
{
goto exit_on_error;
}
write_len += 2;
st = str + 1; // reset start point
}
else if (++write_len >= max_token_len)
{
if ((error = flush_quoted_str (tout, st, ((int) (str - st) + 1))) != NO_ERROR)
{
goto exit_on_error;
}
write_len = 0; // reset the number of characters written per line.
st = str + 1; // reset start point
if ((str + 1) < end && str[1])
{
error = flush_quoted_str (tout, "'+\n '", 5);
if (error != NO_ERROR)
{
goto exit_on_error;
}
}
}
}
if (st < str)
{
if ((error = flush_quoted_str (tout, st, ((int) (str - st)))) != NO_ERROR)
{
goto exit_on_error;
}
}
if (tout->tail_ptr->iosize <= tout->tail_ptr->count)
{
CHECK_PRINT_ERROR (get_text_output_mem (tout, 1));
}
/* closing quote */
tout->tail_ptr->ptr[0] = '\'';
tout->tail_ptr->ptr++;
tout->tail_ptr->count++;
exit_on_end:
return error;
exit_on_error:
CHECK_EXIT_ERROR (error);
return error;
}
#define INTERNAL_BUFFER_SIZE (400) /* bigger than DBL_MAX_DIGITS */
inline bool
need_append_dot (const char *val)
{
while (*val)
{
if (*val == '.' || *val == 'e' || *val == 'E')
{
return false;
}
val++;
}
return true;
}
/*
* fprint_special_strings - print special DB_VALUE to TEXT_OUTPUT
* return: NO_ERROR if successful, error code otherwise
* tout(out): output
* value(in): DB_VALUE
*/
static int
fprint_special_strings (TEXT_OUTPUT * tout, DB_VALUE * value)
{
int error = NO_ERROR;
char buf[INTERNAL_BUFFER_SIZE];
char *ptr;
const char *str_ptr = NULL;
char *json_body = NULL;
DB_TYPE type;
int len;
DB_DATETIMETZ *dt_tz;
DB_TIMESTAMPTZ *ts_tz;
type = DB_VALUE_TYPE (value);
switch (type)
{
case DB_TYPE_NULL:
CHECK_PRINT_ERROR (text_print (tout, "NULL", 4, NULL));
break;
case DB_TYPE_BIGINT:
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "%" PRId64, db_get_bigint (value)));
break;
case DB_TYPE_INTEGER:
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "%d", db_get_int (value)));
break;
case DB_TYPE_SMALLINT:
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "%d", (int) db_get_short (value)));
break;
case DB_TYPE_FLOAT:
case DB_TYPE_DOUBLE:
{
char *pos = NULL;
TEXT_BUFFER_BLK *tail_ptr_bk = NULL;
if (tout->tail_ptr)
{
tail_ptr_bk = tout->tail_ptr;
pos = tout->tail_ptr->ptr;
}
CHECK_PRINT_ERROR (text_print
(tout, NULL, 0, "%.*g", (type == DB_TYPE_FLOAT) ? 10 : 17,
(type == DB_TYPE_FLOAT) ? db_get_float (value) : db_get_double (value)));
/* if tout flushed, then this float/double should be the first content */
if (pos == NULL || tail_ptr_bk != tout->tail_ptr)
{
assert (tout->tail_ptr != NULL);
pos = tout->tail_ptr->buffer;
}
if (need_append_dot (pos))
{
CHECK_PRINT_ERROR (text_print (tout, ".", 1, NULL));
}
}
break;
case DB_TYPE_ENUMERATION:
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "%d", (int) db_get_enum_short (value)));
break;
case DB_TYPE_DATE:
db_date_to_string (buf, INTERNAL_BUFFER_SIZE, db_get_date (value));
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "date '%s'", buf));
break;
case DB_TYPE_TIME:
db_time_to_string (buf, INTERNAL_BUFFER_SIZE, db_get_time (value));
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "time '%s'", buf));
break;
case DB_TYPE_TIMESTAMP:
db_timestamp_to_string (buf, INTERNAL_BUFFER_SIZE, db_get_timestamp (value));
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "timestamp '%s'", buf));
break;
case DB_TYPE_TIMESTAMPLTZ:
db_timestampltz_to_string (buf, INTERNAL_BUFFER_SIZE, db_get_timestamp (value));
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "timestampltz '%s'", buf));
break;
case DB_TYPE_TIMESTAMPTZ:
ts_tz = db_get_timestamptz (value);
db_timestamptz_to_string (buf, INTERNAL_BUFFER_SIZE, &ts_tz->timestamp, &ts_tz->tz_id);
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "timestamptz '%s'", buf));
break;
case DB_TYPE_DATETIME:
db_datetime_to_string (buf, INTERNAL_BUFFER_SIZE, db_get_datetime (value));
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "datetime '%s'", buf));
break;
case DB_TYPE_DATETIMELTZ:
db_datetimeltz_to_string (buf, INTERNAL_BUFFER_SIZE, db_get_datetime (value));
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "datetimeltz '%s'", buf));
break;
case DB_TYPE_DATETIMETZ:
dt_tz = db_get_datetimetz (value);
db_datetimetz_to_string (buf, INTERNAL_BUFFER_SIZE, &dt_tz->datetime, &dt_tz->tz_id);
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "datetimetz '%s'", buf));
break;
case DB_TYPE_MONETARY:
/* Always print symbol before value, even if for turkish lira the user format is after value :
* intl_get_currency_symbol_position */
CHECK_PRINT_ERROR (text_print
(tout, NULL, 0, "%s%.*f", intl_get_money_esc_ISO_symbol (db_get_monetary (value)->type), 2,
db_get_monetary (value)->amount));
break;
case DB_TYPE_CHAR:
case DB_TYPE_VARCHAR:
str_ptr = db_get_string (value);
len = db_get_string_size (value);
if (len < 0)
{
len = (int) strlen (str_ptr);
}
CHECK_PRINT_ERROR (print_quoted_str (tout, str_ptr, len, MAX_DISPLAY_COLUMN));
break;
case DB_TYPE_NUMERIC:
ptr = numeric_db_value_print (value, buf);
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, !strchr (ptr, '.') ? "%s." : "%s", ptr));
break;
case DB_TYPE_BIT:
case DB_TYPE_VARBIT:
{
int max_size = ((db_get_string_length (value) + 3) / 4) + 1;
if (max_size > INTERNAL_BUFFER_SIZE)
{
ptr = (char *) malloc (max_size);
if (ptr == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) max_size);
break; /* FIXME */
}
}
else
{
ptr = buf;
}
if (bfmt_print (1 /* BIT_STRING_HEX */ , value, ptr, max_size) ==
NO_ERROR)
{
CHECK_PRINT_ERROR (text_print (tout, "X", 1, NULL));
CHECK_PRINT_ERROR (print_quoted_str (tout, ptr, max_size - 1, MAX_DISPLAY_COLUMN));
}
if (ptr != buf)
{
free_and_init (ptr);
}
break;
}
/* other stubs */
case DB_TYPE_ERROR:
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "%d", db_get_error (value)));
break;
case DB_TYPE_POINTER:
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "%p", db_get_pointer (value)));
break;
case DB_TYPE_JSON:
json_body = db_get_json_raw_body (value);
CHECK_PRINT_ERROR (text_print (tout, NULL, 0, "'%s'", json_body));
db_private_free (NULL, json_body);
break;
default:
/* the others are handled by callers or internal-use only types */
break;
}
exit_on_end:
return error;
exit_on_error:
CHECK_EXIT_ERROR (error);
goto exit_on_end;
}
/*
* desc_value_special_fprint - Print a description of the given value.
* return: NO_ERROR, if successful, error number, if not successful.
* tout(out): TEXT_OUTPUT
* value(in): value container
* Note:
* This is based on db_value_print() but has extensions for the
* handling of set descriptors, and ELO's used by the desc_ module.
* String printing is also hacked for "unprintable" characters.
*/
int
desc_value_special_fprint (TEXT_OUTPUT * tout, DB_VALUE * value)
{
int error = NO_ERROR;
switch (DB_VALUE_TYPE (value))
{
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
CHECK_PRINT_ERROR (fprint_special_set (tout, db_get_set (value)));
break;
case DB_TYPE_BLOB:
case DB_TYPE_CLOB:
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_MIGDB, MIGDB_MSG_CANT_PRINT_ELO));
break;
default:
CHECK_PRINT_ERROR (fprint_special_strings (tout, value));
break;
}
exit_on_end:
return error;
exit_on_error:
CHECK_EXIT_ERROR (error);
goto exit_on_end;
}
/*
* desc_value_print - Print a description of the given value.
* return: void
* output_ctx(in): output context
* value(in): value container
* Note:
* This is based on db_value_print() but has extensions for the
* handling of set descriptors, and ELO's used by the desc_ module.
* String printing is also hacked for "unprintable" characters.
*/
void
desc_value_print (print_output & output_ctx, DB_VALUE * value)
{
switch (DB_VALUE_TYPE (value))
{
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
print_set (output_ctx, db_get_set (value));
break;
case DB_TYPE_BLOB:
case DB_TYPE_CLOB:
fprintf (stderr, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_MIGDB, MIGDB_MSG_CANT_PRINT_ELO));
break;
default:
db_print_value (output_ctx, value);
break;
}
}
/*
* text_print - print formatted text to TEXT_OUTPUT
* return: NO_ERROR if successful, error code otherwise
* tout(out): TEXT_OUTPUT
* buf(in): source buffer
* buflen(in): length of buffer
* fmt(in): format string
* ...(in): arguments
*/
int
text_print (TEXT_OUTPUT * tout, const char *buf, int buflen, char const *fmt, ...)
{
int error = NO_ERROR;
int nbytes, size;
va_list ap;
assert (buflen >= 0);
if (tout->tail_ptr == NULL)
{
assert (tout->head_ptr == NULL);
CHECK_PRINT_ERROR (get_text_output_mem (tout, ((buflen > 0) ? buflen : -1)));
}
size = tout->tail_ptr->iosize - tout->tail_ptr->count; /* free space size */
if (buflen > 0)
{
int tlen = 0;
assert (buf != NULL);
while (buflen >= size)
{
memcpy (tout->tail_ptr->ptr, buf + tlen, size);
*(tout->tail_ptr->ptr + size) = '\0'; /* Null terminate */
tout->tail_ptr->ptr += size;
tout->tail_ptr->count += size;
buflen -= size;
tlen += size;
CHECK_PRINT_ERROR (get_text_output_mem (tout, buflen));
size = tout->tail_ptr->iosize;
}
if (buflen > 0)
{
memcpy (tout->tail_ptr->ptr, buf + tlen, buflen);
*(tout->tail_ptr->ptr + buflen) = '\0'; /* Null terminate */
tout->tail_ptr->ptr += buflen;
tout->tail_ptr->count += buflen;
}
}
else
{
va_start (ap, fmt);
nbytes = vsnprintf (tout->tail_ptr->ptr, size, fmt, ap);
va_end (ap);
if (nbytes < 0)
return ER_FAILED;
if (nbytes >= size)
{
CHECK_PRINT_ERROR (get_text_output_mem (tout, nbytes));
size = tout->tail_ptr->iosize;
va_start (ap, fmt);
nbytes = vsnprintf (tout->tail_ptr->ptr, size, fmt, ap);
va_end (ap);
if (nbytes < 0)
return ER_FAILED;
}
assert (nbytes < size);
tout->tail_ptr->ptr += nbytes;
tout->tail_ptr->count += nbytes;
}
return error;
exit_on_error:
CHECK_EXIT_ERROR (error);
return error;
}
int
text_print_request_flush (TEXT_OUTPUT * tout, bool force)
{
TEXT_BUFFER_BLK *tp, *head;
if (tout == NULL || tout->head_ptr == NULL)
{
return NO_ERROR;
}
head = tout->head_ptr;
if (head->count <= 0)
{
// empty block
while (head)
{
tp = head;
head = head->next;
c_text_buf_mgr.release_text_buffer (tp);
}
tout->head_ptr = NULL;
tout->tail_ptr = NULL;
tout->record_cnt = 0;
return NO_ERROR;
}
if (!g_multi_thread_mode && g_fd_handle != INVALID_FILE_NO)
{
tout->head_ptr = NULL;
tout->tail_ptr = NULL;
tout->record_cnt = 0;
return write_object_file (head);
}
int flag = 0;
tout->record_cnt++;
if (force || head->next || ((head->iosize - head->count) < (((double) head->count / tout->record_cnt) * 1.5)))
{
do
{
if (c_write_blk_queue.enqueue (head))
{
break;
}
if (flag == 0)
{
TIMER_BEGIN ((g_sampling_records >= 0), &(g_thr_param[tout->ref_thread_param_idx].wi_add_Q));
flag++;
}
YIELD_THREAD ();
if (error_occurred)
{
return ER_FAILED;
}
}
while (true);
if (flag)
{
TIMER_END ((g_sampling_records >= 0), &(g_thr_param[tout->ref_thread_param_idx].wi_add_Q));
}
tout->head_ptr = NULL;
tout->tail_ptr = NULL;
tout->record_cnt = 0;
}
return NO_ERROR;
}
static int
write_object_file (TEXT_BUFFER_BLK * head)
{
TEXT_BUFFER_BLK *tp;
int error = NO_ERROR;
int _errno;
TIMER_BEGIN ((g_sampling_records >= 0), &wi_write_file);
for (tp = head; tp && tp->count > 0; tp = head)
{
head = tp->next;
/* write to disk */
if (error == NO_ERROR)
{
if (tp->count != write (g_fd_handle, tp->buffer, tp->count))
{
#if defined(WINDOWS)
_errno = _doserrno;
#else
_errno = errno;
#endif
// TODDO: EAGAIN, EINTR ?
assert (_errno == EINTR || _errno == EBADF);
error = ER_IO_WRITE;
}
}
c_text_buf_mgr.release_text_buffer (tp);
}
TIMER_END ((g_sampling_records >= 0), &wi_write_file);
return error;
}
#if !defined(WINDOWS)
void
timespec_diff (struct timespec *start, struct timespec *end, struct timespec *diff)
{
diff->tv_sec = end->tv_sec - start->tv_sec;
diff->tv_nsec = end->tv_nsec - start->tv_nsec;
if (diff->tv_nsec < 0)
{
diff->tv_sec--;
diff->tv_nsec += NANO_PREC_VAL;
}
}
void
timespec_accumulate (struct timespec *ts_sum, struct timespec *ts_start)
{
struct timespec te, tdiff;
clock_gettime (CLOCK_MONOTONIC /* CLOCK_REALTIME */ , &te);
timespec_diff (ts_start, &te, &tdiff);
ts_sum->tv_sec += tdiff.tv_sec;
ts_sum->tv_nsec += tdiff.tv_nsec;
while (ts_sum->tv_nsec >= NANO_PREC_VAL)
{
ts_sum->tv_sec++;
ts_sum->tv_nsec -= NANO_PREC_VAL;
}
}
void
timespec_addup (struct timespec *ts_sum, struct timespec *ts_add)
{
ts_sum->tv_sec += ts_add->tv_sec;
ts_sum->tv_nsec += ts_add->tv_nsec;
while (ts_sum->tv_nsec >= NANO_PREC_VAL)
{
ts_sum->tv_sec++;
ts_sum->tv_nsec -= NANO_PREC_VAL;
}
}
void
print_message_with_time (FILE * fp, const char *msg)
{
struct timespec specific_time;
struct tm *now;
if (fp == NULL)
{
return;
}
clock_gettime (CLOCK_REALTIME, &specific_time);
now = localtime (&specific_time.tv_sec);
fprintf (fp, "time: %04d/%02d/%02d %02d:%02d:%02d.%09ld, %s\n", 1900 + now->tm_year,
now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec, specific_time.tv_nsec,
(msg ? msg : ""));
}
#endif