/* * parser_allocate_string_buffer () - creates memory for a given parser * return: allocated memory pointer * parser(in): * length(in): * align(in): * * Note : * First it tries to find length + 1 bytes in the parser's free strings list. * If there is no room, it adds a new block of strings to the free * strings list, at least large enough to hold new length plus * 1 (for a null character). Thus, one can call it by * copy_of_foo = pt_create_string(parser, strlen(foo)); */ void * parser_allocate_string_buffer (const PARSER_CONTEXT * parser, const int length, const int align) { int idhash; PARSER_STRING_BLOCK *block; #if defined(SERVER_MODE) int rv; #endif /* SERVER_MODE */ /* find free string list for for this id */ idhash = parser->id % HASH_NUMBER; #if defined(SERVER_MODE) MUTEX_LOCK (rv, parser_memory_lock); #endif /* SERVER_MODE */ block = parser_String_blocks[idhash]; while (block != NULL && (block->parser_id != parser->id || ((block->block_end - block->last_string_end) < (length + (align - 1) + 1)))) { block = block->next; } #if defined(SERVER_MODE) MUTEX_UNLOCK (parser_memory_lock); #endif /* SERVER_MODE */ if (block == NULL) { if ((block = parser_create_string_block (parser, length + (align - 1) + 1)) == NULL) return NULL; } /* set start to the aligned length */ block->last_string_start = CAST_BUFLEN ((block->last_string_end + (align - 1) + 1) & ~(align - 1)); block->last_string_end = CAST_BUFLEN (block->last_string_start + length); block->u.chars[block->last_string_start] = 0; return &block->u.chars[block->last_string_start]; }
/* * overflow_get_nbytes () - GET A PORTION OF THE CONTENT OF AN OVERFLOW RECORD * return: scan status * ovf_vpid(in): Overflow address * recdes(in): Record descriptor * start_offset(in): Start offset of portion to copy * max_nbytes(in): Maximum number of bytes to retrieve * remaining_length(in): The number of remaining bytes to read * * Note: A portion of the content of the overflow record associated with the * given overflow address(ovf_pid) is placed into the area pointed to by * the record descriptor. If the content of the object does not fit in * such an area (i.e., recdes->area_size), an error is returned and a * hint of the number of bytes needed is returned as a negative value in * recdes->length. The length of the retrieved number of bytes is *set * in the the record descriptor (i.e., recdes->length). */ SCAN_CODE overflow_get_nbytes (THREAD_ENTRY * thread_p, const VPID * ovf_vpid, RECDES * recdes, int start_offset, int max_nbytes, int *remaining_length) { OVERFLOW_FIRST_PART *first_part; OVERFLOW_REST_PART *rest_parts; PAGE_PTR pgptr = NULL; char *copyfrom; VPID next_vpid; int copy_length; char *data; /* * We don't need to lock the overflow pages since these pages are not * shared among several pieces of overflow data. The overflow pages are * know by accessing the relocation-overflow record with the appropiate lock */ next_vpid = *ovf_vpid; pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { return S_ERROR; } first_part = (OVERFLOW_FIRST_PART *) pgptr; *remaining_length = first_part->length; if (max_nbytes < 0) { /* The rest of the overflow record starting at start_offset */ max_nbytes = *remaining_length - start_offset; } else { /* Don't give more than what we have */ if (max_nbytes > (*remaining_length - start_offset)) { max_nbytes = *remaining_length - start_offset; } } if (max_nbytes < 0) { /* Likely the offset was beyond the size of the overflow record */ max_nbytes = 0; *remaining_length = 0; } else { *remaining_length -= max_nbytes; } /* Make sure that there is enough space to copy the desired length object */ if (max_nbytes > recdes->area_size) { pgbuf_unfix_and_init (thread_p, pgptr); /* Give a hint to the user of the needed length. Hint is given as a negative value */ recdes->length = -max_nbytes; return S_DOESNT_FIT; } else if (max_nbytes == 0) { pgbuf_unfix_and_init (thread_p, pgptr); recdes->length = 0; return S_SUCCESS; } recdes->length = max_nbytes; /* Start copying the object */ data = recdes->data; copyfrom = (char *) first_part->data; next_vpid = first_part->next_vpid; while (max_nbytes > 0) { /* Continue seeking until the starting offset is reached (passed) */ if (start_offset > 0) { /* Advance .. seek as much as you can */ copy_length = (int) ((copyfrom + start_offset) > ((char *) pgptr + DB_PAGESIZE) ? DB_PAGESIZE - (copyfrom - (char *) pgptr) : start_offset); start_offset -= copy_length; copyfrom += copy_length; } /* * Copy as much as you can when you do not need to continue seeking, * and there is something to copy in current page (i.e., not at end * of the page) and we are not located at the end of the overflow record. */ if (start_offset == 0) { if (copyfrom + max_nbytes > (char *) pgptr + DB_PAGESIZE) { copy_length = DB_PAGESIZE - CAST_BUFLEN (copyfrom - (char *) pgptr); } else { copy_length = max_nbytes; } /* If we were not at the end of the page, perform the copy */ if (copy_length > 0) { memcpy (data, copyfrom, copy_length); data += copy_length; max_nbytes -= copy_length; } } pgbuf_unfix_and_init (thread_p, pgptr); if (max_nbytes > 0) { if (VPID_ISNULL (&next_vpid)) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_HEAP_OVFADDRESS_CORRUPTED, 3, ovf_vpid->volid, ovf_vpid->pageid, NULL_SLOTID); return S_ERROR; } pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { recdes->length = 0; return S_ERROR; } rest_parts = (OVERFLOW_REST_PART *) pgptr; copyfrom = (char *) rest_parts->data; next_vpid = rest_parts->next_vpid; } } return S_SUCCESS; }
/* * overflow_insert () - Insert a multipage data in overflow * return: ovf_vpid on success or NULL on failure * ovf_vfid(in): File where the overflow data is going to be stored * ovf_vpid(out): Overflow address * recdes(in): Record descriptor * * Note: Data in overflow is composed of several pages. Pages in the overflow * area are not shared among other pieces of overflow data. * * -------------------------------- ------------------------ * |Next_vpid |Length|... data ...| ... --> |Next_vpid|... data ...| * -------------------------------- ------------------------ * * Single link list of pages. * The length of the multipage data is stored on its first overflow page * * Overflow pages are not locked in any mode since they are not shared * by other pieces of data and its address is only know by accessing the * relocation overflow record data which has been appropriately locked. */ VPID * overflow_insert (THREAD_ENTRY * thread_p, const VFID * ovf_vfid, VPID * ovf_vpid, RECDES * recdes) { PAGE_PTR vfid_fhdr_pgptr = NULL; OVERFLOW_FIRST_PART *first_part; OVERFLOW_REST_PART *rest_parts; OVERFLOW_RECV_LINKS undo_recv; char *copyto; int length, copy_length; INT32 npages = 0; char *data; int alloc_nth; LOG_DATA_ADDR addr; LOG_DATA_ADDR logical_undoaddr; int i; VPID *vpids, fhdr_vpid; VPID vpids_buffer[OVERFLOW_ALLOCVPID_ARRAY_SIZE + 1]; FILE_ALLOC_VPIDS alloc_vpids; /* * We don't need to lock the overflow pages since these pages are not * shared among several pieces of overflow data. The overflow pages are * know by accessing the relocation-overflow record with the appropiate lock */ addr.vfid = ovf_vfid; addr.offset = 0; logical_undoaddr.vfid = ovf_vfid; logical_undoaddr.offset = 0; logical_undoaddr.pgptr = NULL; undo_recv.ovf_vfid = *ovf_vfid; /* * Temporary: * Lock the file header, so I am the only one changing the file table * of allocated pages. This is needed since this function is using * file_find_nthpages, which could give me not the expected page, if someone * else remove pages, after the initial allocation. */ fhdr_vpid.volid = ovf_vfid->volid; fhdr_vpid.pageid = ovf_vfid->fileid; vfid_fhdr_pgptr = pgbuf_fix (thread_p, &fhdr_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH); if (vfid_fhdr_pgptr == NULL) { return NULL; } /* * Guess the number of pages. The total number of pages is found by * dividing length by pagesize - the smallest header. Then, we make sure * that this estimate is correct. */ length = recdes->length - (DB_PAGESIZE - (int) offsetof (OVERFLOW_FIRST_PART, data)); if (length > 0) { i = DB_PAGESIZE - offsetof (OVERFLOW_REST_PART, data); npages = 1 + CEIL_PTVDIV (length, i); } else { npages = 1; } if (npages > OVERFLOW_ALLOCVPID_ARRAY_SIZE) { vpids = (VPID *) malloc ((npages + 1) * sizeof (VPID)); if (vpids == NULL) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (npages + 1) * sizeof (VPID)); pgbuf_unfix (thread_p, vfid_fhdr_pgptr); return NULL; } } else { vpids = vpids_buffer; } #if !defined(NDEBUG) for (i = 0; i < npages; i++) { VPID_SET_NULL (&vpids[i]); } #endif VPID_SET_NULL (&vpids[npages]); alloc_vpids.vpids = vpids; alloc_vpids.index = 0; /* * We do not initialize the pages during allocation since they are not * pointed by anyone until we return from this function, at that point * they are initialized. */ if (file_alloc_pages_as_noncontiguous (thread_p, ovf_vfid, vpids, &alloc_nth, npages, NULL, NULL, NULL, &alloc_vpids) == NULL) { if (vpids != vpids_buffer) { free_and_init (vpids); } pgbuf_unfix (thread_p, vfid_fhdr_pgptr); return NULL; } assert (alloc_vpids.index == npages); #if !defined(NDEBUG) for (i = 0; i < npages; i++) { assert (!VPID_ISNULL (&vpids[i])); } #endif *ovf_vpid = vpids[0]; /* Copy the content of the data */ data = recdes->data; length = recdes->length; for (i = 0; i < npages; i++) { addr.pgptr = pgbuf_fix (thread_p, &vpids[i], NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH); if (addr.pgptr == NULL) { goto exit_on_error; } /* Is this the first page ? */ if (i == 0) { /* This is the first part */ first_part = (OVERFLOW_FIRST_PART *) addr.pgptr; first_part->next_vpid = vpids[i + 1]; first_part->length = length; copyto = (char *) first_part->data; copy_length = DB_PAGESIZE - offsetof (OVERFLOW_FIRST_PART, data); if (length < copy_length) { copy_length = length; } /* notify the first part of overflow recdes */ log_append_empty_record (thread_p, LOG_DUMMY_OVF_RECORD); } else { rest_parts = (OVERFLOW_REST_PART *) addr.pgptr; rest_parts->next_vpid = vpids[i + 1]; copyto = (char *) rest_parts->data; copy_length = DB_PAGESIZE - offsetof (OVERFLOW_REST_PART, data); if (length < copy_length) { copy_length = length; } } memcpy (copyto, data, copy_length); data += copy_length; length -= copy_length; pgbuf_get_vpid (addr.pgptr, &undo_recv.new_vpid); if (file_is_new_file (thread_p, ovf_vfid) == FILE_OLD_FILE) { /* we don't do undo logging for new files */ log_append_undo_data (thread_p, RVOVF_NEWPAGE_LOGICAL_UNDO, &logical_undoaddr, sizeof (undo_recv), &undo_recv); } log_append_redo_data (thread_p, RVOVF_NEWPAGE_INSERT, &addr, copy_length + CAST_BUFLEN (copyto - (char *) addr.pgptr), (char *) addr.pgptr); pgbuf_set_dirty (thread_p, addr.pgptr, FREE); addr.pgptr = NULL; } assert (length == 0); #if defined (CUBRID_DEBUG) if (length > 0) { er_log_debug (ARG_FILE_LINE, "ovf_insert: ** SYSTEM ERROR calculation" " of number of pages needed to store overflow data seems" " incorrect. Need no more than %d pages", npages); goto exit_on_error; } #endif /* * Temporary: * Unlock the file header, so I am the only one changing the file table * of allocated pages. This is needed since curently, I am using * file_find_nthpages, which could give me not the expected page, if someone * else remove pages. */ if (vpids != vpids_buffer) { free_and_init (vpids); } pgbuf_unfix (thread_p, vfid_fhdr_pgptr); return ovf_vpid; exit_on_error: for (i = 0; i < npages; i++) { (void) file_dealloc_page (thread_p, ovf_vfid, &vpids[i]); } if (vpids != vpids_buffer) { free_and_init (vpids); } pgbuf_unfix (thread_p, vfid_fhdr_pgptr); return NULL; }
/* * parser_create_string_block () - reates a new block of strings, links the block * on the hash list for the parser, and returns the block * return: * parser(in): * length(in): */ static PARSER_STRING_BLOCK * parser_create_string_block (const PARSER_CONTEXT * parser, const int length) { int idhash; PARSER_STRING_BLOCK *block; #if defined(SERVER_MODE) int rv; #endif /* SERVER_MODE */ if (length < (int) STRINGS_PER_BLOCK) { block = (PARSER_STRING_BLOCK *) malloc (sizeof (PARSER_STRING_BLOCK)); if (!block) { if (parser->jmp_env_active) { /* long jump back to routine that set up the jump env * for clean up and run down. */ longjmp (((PARSER_CONTEXT *) parser)->jmp_env, 1); } else { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (PARSER_STRING_BLOCK)); return NULL; } } block->block_end = STRINGS_PER_BLOCK - 1; } else { /* This is an unusually large string. Allocate a special block * for it, with space for one string, plus some space * for appending to. */ block = (PARSER_STRING_BLOCK *) malloc (sizeof (PARSER_STRING_BLOCK) + (length + 1001 - STRINGS_PER_BLOCK)); if (!block) { if (parser->jmp_env_active) { /* long jump back to routine that set up the jump env * for clean up and run down. */ longjmp (((PARSER_CONTEXT *) parser)->jmp_env, 1); } else { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (sizeof (PARSER_STRING_BLOCK) + (length + 1001 - STRINGS_PER_BLOCK))); return NULL; } } block->block_end = CAST_BUFLEN (length + 1001 - 1); } /* remember which parser allocated this block */ block->parser_id = parser->id; block->last_string_start = -1; block->last_string_end = -1; block->u.chars[0] = 0; /* link blocks on the hash list for this id */ idhash = parser->id % HASH_NUMBER; #if defined(SERVER_MODE) MUTEX_LOCK (rv, parser_memory_lock); #endif /* SERVER_MODE */ block->next = parser_String_blocks[idhash]; parser_String_blocks[idhash] = block; #if defined(SERVER_MODE) MUTEX_UNLOCK (parser_memory_lock); #endif /* SERVER_MODE */ return block; }