int Dbtup::tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageIndex, Uint32* dataOut, bool xfrmFlag) { jamEntry(); // use own variables instead of globals FragrecordPtr fragPtr; fragPtr.i= fragPtrI; ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); TablerecPtr tablePtr; tablePtr.i= fragPtr.p->fragTableId; ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec); Operationrec tmpOp; tmpOp.m_tuple_location.m_page_no= pageId; tmpOp.m_tuple_location.m_page_idx= pageIndex; KeyReqStruct req_struct(this); req_struct.tablePtrP = tablePtr.p; req_struct.fragPtrP = fragPtr.p; PagePtr page_ptr; Uint32* ptr= get_ptr(&page_ptr, &tmpOp.m_tuple_location, tablePtr.p); req_struct.m_page_ptr = page_ptr; req_struct.m_tuple_ptr = (Tuple_header*)ptr; int ret = 0; if (! (req_struct.m_tuple_ptr->m_header_bits & Tuple_header::FREE)) { req_struct.check_offset[MM]= tablePtr.p->get_check_offset(MM); req_struct.check_offset[DD]= tablePtr.p->get_check_offset(DD); Uint32 num_attr= tablePtr.p->m_no_of_attributes; Uint32 descr_start= tablePtr.p->tabDescriptor; TableDescriptor *tab_descr= &tableDescriptor[descr_start]; ndbrequire(descr_start + (num_attr << ZAD_LOG_SIZE) <= cnoOfTabDescrRec); req_struct.attr_descr= tab_descr; if(req_struct.m_tuple_ptr->m_header_bits & Tuple_header::ALLOC) { Uint32 opPtrI= req_struct.m_tuple_ptr->m_operation_ptr_i; Operationrec* opPtrP= c_operation_pool.getPtr(opPtrI); ndbassert(!opPtrP->m_copy_tuple_location.isNull()); req_struct.m_tuple_ptr= get_copy_tuple(&opPtrP->m_copy_tuple_location); } prepare_read(&req_struct, tablePtr.p, false); const Uint32* attrIds= &tableDescriptor[tablePtr.p->readKeyArray].tabDescr; const Uint32 numAttrs= tablePtr.p->noOfKeyAttr; // read pk attributes from original tuple // do it ret = readAttributes(&req_struct, attrIds, numAttrs, dataOut, ZNIL, xfrmFlag); // done if (ret >= 0) { // remove headers Uint32 n= 0; Uint32 i= 0; while (n < numAttrs) { const AttributeHeader ah(dataOut[i]); Uint32 size= ah.getDataSize(); ndbrequire(size != 0); for (Uint32 j= 0; j < size; j++) { dataOut[i + j - n]= dataOut[i + j + 1]; } n+= 1; i+= 1 + size; } ndbrequire((int)i == ret); ret -= numAttrs; } else { return ret; } } if (tablePtr.p->m_bits & Tablerec::TR_RowGCI) { dataOut[ret] = *req_struct.m_tuple_ptr->get_mm_gci(tablePtr.p); } else { dataOut[ret] = 0; } return ret; }
int Dbtup::tuxReadAttrs(EmulatedJamBuffer * jamBuf, Uint32 fragPtrI, Uint32 pageId, Uint32 pageIndex, Uint32 tupVersion, const Uint32* attrIds, Uint32 numAttrs, Uint32* dataOut, bool xfrmFlag) { thrjamEntry(jamBuf); // use own variables instead of globals FragrecordPtr fragPtr; fragPtr.i= fragPtrI; ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); TablerecPtr tablePtr; tablePtr.i= fragPtr.p->fragTableId; ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec); // search for tuple version if not original Operationrec tmpOp; KeyReqStruct req_struct(jamBuf); req_struct.tablePtrP = tablePtr.p; req_struct.fragPtrP = fragPtr.p; tmpOp.m_tuple_location.m_page_no= pageId; tmpOp.m_tuple_location.m_page_idx= pageIndex; tmpOp.op_type = ZREAD; // valgrind setup_fixed_tuple_ref(&req_struct, &tmpOp, tablePtr.p); setup_fixed_part(&req_struct, &tmpOp, tablePtr.p); Tuple_header *tuple_ptr= req_struct.m_tuple_ptr; if (tuple_ptr->get_tuple_version() != tupVersion) { jam(); OperationrecPtr opPtr; opPtr.i= tuple_ptr->m_operation_ptr_i; Uint32 loopGuard= 0; while (opPtr.i != RNIL) { c_operation_pool.getPtr(opPtr); if (opPtr.p->op_struct.bit_field.tupVersion == tupVersion) { jam(); if (!opPtr.p->m_copy_tuple_location.isNull()) { req_struct.m_tuple_ptr= get_copy_tuple(&opPtr.p->m_copy_tuple_location); } break; } jam(); opPtr.i= opPtr.p->prevActiveOp; ndbrequire(++loopGuard < (1 << ZTUP_VERSION_BITS)); } } // read key attributes from found tuple version // save globals prepare_read(&req_struct, tablePtr.p, false); // do it int ret = readAttributes(&req_struct, attrIds, numAttrs, dataOut, ZNIL, xfrmFlag); // done return ret; }
void Dbtup::commit_operation(Signal* signal, Uint32 gci_hi, Uint32 gci_lo, Tuple_header* tuple_ptr, PagePtr pagePtr, Operationrec* regOperPtr, Fragrecord* regFragPtr, Tablerec* regTabPtr) { ndbassert(regOperPtr->op_type != ZDELETE); Uint32 lcpScan_ptr_i= regFragPtr->m_lcp_scan_op; Uint32 save= tuple_ptr->m_operation_ptr_i; Uint32 bits= tuple_ptr->m_header_bits; Tuple_header *disk_ptr= 0; Tuple_header *copy= get_copy_tuple(®OperPtr->m_copy_tuple_location); Uint32 copy_bits= copy->m_header_bits; Uint32 fixsize= regTabPtr->m_offsets[MM].m_fix_header_size; Uint32 mm_vars= regTabPtr->m_attributes[MM].m_no_of_varsize; Uint32 mm_dyns= regTabPtr->m_attributes[MM].m_no_of_dynamic; bool update_gci_at_commit = ! regOperPtr->op_struct.bit_field.m_gci_written; if((mm_vars+mm_dyns) == 0) { jam(); memcpy(tuple_ptr, copy, 4*fixsize); disk_ptr= (Tuple_header*)(((Uint32*)copy)+fixsize); } else { jam(); /** * Var_part_ref is only stored in *allocated* tuple * so memcpy from copy, will over write it... * hence subtle copyout/assign... */ Local_key tmp; Var_part_ref *ref= tuple_ptr->get_var_part_ref_ptr(regTabPtr); ref->copyout(&tmp); memcpy(tuple_ptr, copy, 4*fixsize); ref->assign(&tmp); PagePtr vpagePtr; if (copy_bits & Tuple_header::VAR_PART) { jam(); ndbassert(bits & Tuple_header::VAR_PART); ndbassert(tmp.m_page_no != RNIL); ndbassert(copy_bits & Tuple_header::COPY_TUPLE); Uint32 *dst= get_ptr(&vpagePtr, *ref); Var_page* vpagePtrP = (Var_page*)vpagePtr.p; Varpart_copy*vp =(Varpart_copy*)copy->get_end_of_fix_part_ptr(regTabPtr); /* The first word of shrunken tuple holds the lenght in words. */ Uint32 len = vp->m_len; memcpy(dst, vp->m_data, 4*len); if(copy_bits & Tuple_header::MM_SHRINK) { jam(); ndbassert(vpagePtrP->get_entry_len(tmp.m_page_idx) >= len); if (len) { jam(); ndbassert(regFragPtr->m_varWordsFree >= vpagePtrP->free_space); regFragPtr->m_varWordsFree -= vpagePtrP->free_space; vpagePtrP->shrink_entry(tmp.m_page_idx, len); // Adds the new free space value for the page to the fragment total. update_free_page_list(regFragPtr, vpagePtr); } else { jam(); free_var_part(regFragPtr, vpagePtr, tmp.m_page_idx); tmp.m_page_no = RNIL; ref->assign(&tmp); copy_bits &= ~(Uint32)Tuple_header::VAR_PART; } } else { jam(); ndbassert(vpagePtrP->get_entry_len(tmp.m_page_idx) == len); } /** * Find disk part after * header + fixed MM part + length word + varsize part. */ disk_ptr = (Tuple_header*)(vp->m_data + len); } else { jam(); ndbassert(tmp.m_page_no == RNIL); disk_ptr = (Tuple_header*)copy->get_end_of_fix_part_ptr(regTabPtr); } } if (regTabPtr->m_no_of_disk_attributes && (copy_bits & Tuple_header::DISK_INLINE)) { jam(); Local_key key; memcpy(&key, copy->get_disk_ref_ptr(regTabPtr), sizeof(Local_key)); Uint32 logfile_group_id= regFragPtr->m_logfile_group_id; PagePtr diskPagePtr((Tup_page*)m_pgman_ptr.p, m_pgman_ptr.i); ndbassert(diskPagePtr.p->m_page_no == key.m_page_no); ndbassert(diskPagePtr.p->m_file_no == key.m_file_no); Uint32 sz, *dst; if(copy_bits & Tuple_header::DISK_ALLOC) { jam(); disk_page_alloc(signal, regTabPtr, regFragPtr, &key, diskPagePtr, gci_hi); } if(regTabPtr->m_attributes[DD].m_no_of_varsize == 0) { jam(); sz= regTabPtr->m_offsets[DD].m_fix_header_size; dst= ((Fix_page*)diskPagePtr.p)->get_ptr(key.m_page_idx, sz); } else { jam(); dst= ((Var_page*)diskPagePtr.p)->get_ptr(key.m_page_idx); sz= ((Var_page*)diskPagePtr.p)->get_entry_len(key.m_page_idx); } if(! (copy_bits & Tuple_header::DISK_ALLOC)) { jam(); disk_page_undo_update(diskPagePtr.p, &key, dst, sz, gci_hi, logfile_group_id); } memcpy(dst, disk_ptr, 4*sz); memcpy(tuple_ptr->get_disk_ref_ptr(regTabPtr), &key, sizeof(Local_key)); ndbassert(! (disk_ptr->m_header_bits & Tuple_header::FREE)); copy_bits |= Tuple_header::DISK_PART; } if(lcpScan_ptr_i != RNIL && (bits & Tuple_header::ALLOC)) { jam(); ScanOpPtr scanOp; c_scanOpPool.getPtr(scanOp, lcpScan_ptr_i); Local_key rowid = regOperPtr->m_tuple_location; rowid.m_page_no = pagePtr.p->frag_page_id; if (!is_rowid_lcp_scanned(rowid, *scanOp.p)) { jam(); copy_bits |= Tuple_header::LCP_SKIP; } } Uint32 clear= Tuple_header::ALLOC | Tuple_header::FREE | Tuple_header::COPY_TUPLE | Tuple_header::DISK_ALLOC | Tuple_header::DISK_INLINE | Tuple_header::MM_SHRINK | Tuple_header::MM_GROWN; copy_bits &= ~(Uint32)clear; tuple_ptr->m_header_bits= copy_bits; tuple_ptr->m_operation_ptr_i= save; if (regTabPtr->m_bits & Tablerec::TR_RowGCI && update_gci_at_commit) { jam(); * tuple_ptr->get_mm_gci(regTabPtr) = gci_hi; if (regTabPtr->m_bits & Tablerec::TR_ExtraRowGCIBits) { Uint32 attrId = regTabPtr->getExtraAttrId<Tablerec::TR_ExtraRowGCIBits>(); store_extra_row_bits(attrId, regTabPtr, tuple_ptr, gci_lo, /* truncate */true); } } if (regTabPtr->m_bits & Tablerec::TR_Checksum) { jam(); setChecksum(tuple_ptr, regTabPtr); } }
/* ----------------------------------------------------------------- */ void Dbtup::execTUP_COMMITREQ(Signal* signal) { FragrecordPtr regFragPtr; OperationrecPtr regOperPtr; TablerecPtr regTabPtr; KeyReqStruct req_struct(this, KRS_COMMIT); TransState trans_state; Uint32 no_of_fragrec, no_of_tablerec; TupCommitReq * const tupCommitReq= (TupCommitReq *)signal->getDataPtr(); regOperPtr.i= tupCommitReq->opPtr; Uint32 hash_value= tupCommitReq->hashValue; Uint32 gci_hi = tupCommitReq->gci_hi; Uint32 gci_lo = tupCommitReq->gci_lo; Uint32 transId1 = tupCommitReq->transId1; Uint32 transId2 = tupCommitReq->transId2; jamEntry(); c_operation_pool.getPtr(regOperPtr); regFragPtr.i= regOperPtr.p->fragmentPtr; trans_state= get_trans_state(regOperPtr.p); no_of_fragrec= cnoOfFragrec; ndbrequire(trans_state == TRANS_STARTED); ptrCheckGuard(regFragPtr, no_of_fragrec, fragrecord); no_of_tablerec= cnoOfTablerec; regTabPtr.i= regFragPtr.p->fragTableId; req_struct.signal= signal; req_struct.hash_value= hash_value; req_struct.gci_hi = gci_hi; req_struct.gci_lo = gci_lo; /* Put transid in req_struct, so detached triggers can access it */ req_struct.trans_id1 = transId1; req_struct.trans_id2 = transId2; req_struct.m_reorg = regOperPtr.p->op_struct.bit_field.m_reorg; regOperPtr.p->m_commit_disk_callback_page = tupCommitReq->diskpage; #ifdef VM_TRACE if (tupCommitReq->diskpage == RNIL) { m_pgman_ptr.i = RNIL; m_pgman_ptr.p = 0; req_struct.m_disk_page_ptr.i = RNIL; req_struct.m_disk_page_ptr.p = 0; } #endif ptrCheckGuard(regTabPtr, no_of_tablerec, tablerec); PagePtr page; Tuple_header* tuple_ptr= (Tuple_header*) get_ptr(&page, ®OperPtr.p->m_tuple_location, regTabPtr.p); /** * NOTE: This has to be run before potential time-slice when * waiting for disk, as otherwise the "other-ops" in a multi-op * commit might run while we're waiting for disk * */ if (!regTabPtr.p->tuxCustomTriggers.isEmpty()) { if(get_tuple_state(regOperPtr.p) == TUPLE_PREPARED) { jam(); OperationrecPtr loopPtr = regOperPtr; if (unlikely(!regOperPtr.p->is_first_operation())) { findFirstOp(loopPtr); } /** * Execute all tux triggers at first commit * since previous tuple is otherwise removed... */ jam(); goto first; while(loopPtr.i != RNIL) { c_operation_pool.getPtr(loopPtr); first: executeTuxCommitTriggers(signal, loopPtr.p, regFragPtr.p, regTabPtr.p); set_tuple_state(loopPtr.p, TUPLE_TO_BE_COMMITTED); loopPtr.i = loopPtr.p->nextActiveOp; } } } bool get_page = false; if(regOperPtr.p->op_struct.bit_field.m_load_diskpage_on_commit) { jam(); Page_cache_client::Request req; /** * Only last op on tuple needs "real" commit, * hence only this one should have m_load_diskpage_on_commit */ ndbassert(tuple_ptr->m_operation_ptr_i == regOperPtr.i); /** * Check for page */ if(!regOperPtr.p->m_copy_tuple_location.isNull()) { jam(); Tuple_header* tmp= get_copy_tuple(®OperPtr.p->m_copy_tuple_location); memcpy(&req.m_page, tmp->get_disk_ref_ptr(regTabPtr.p), sizeof(Local_key)); if (unlikely(regOperPtr.p->op_type == ZDELETE && tmp->m_header_bits & Tuple_header::DISK_ALLOC)) { jam(); /** * Insert+Delete */ regOperPtr.p->op_struct.bit_field.m_load_diskpage_on_commit = 0; regOperPtr.p->op_struct.bit_field.m_wait_log_buffer = 0; disk_page_abort_prealloc(signal, regFragPtr.p, &req.m_page, req.m_page.m_page_idx); D("Logfile_client - execTUP_COMMITREQ"); Logfile_client lgman(this, c_lgman, regFragPtr.p->m_logfile_group_id); lgman.free_log_space(regOperPtr.p->m_undo_buffer_space); goto skip_disk; if (0) ndbout_c("insert+delete"); jamEntry(); goto skip_disk; } } else { jam(); // initial delete ndbassert(regOperPtr.p->op_type == ZDELETE); memcpy(&req.m_page, tuple_ptr->get_disk_ref_ptr(regTabPtr.p), sizeof(Local_key)); ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART); } if (retrieve_data_page(signal, req, regOperPtr) == 0) { return; // Data page has not been retrieved yet. } get_page = true; } if(regOperPtr.p->op_struct.bit_field.m_wait_log_buffer) { jam(); /** * Only last op on tuple needs "real" commit, * hence only this one should have m_wait_log_buffer */ ndbassert(tuple_ptr->m_operation_ptr_i == regOperPtr.i); if (retrieve_log_page(signal, regFragPtr, regOperPtr) == 0) { return; // Log page has not been retrieved yet. } } assert(tuple_ptr); skip_disk: req_struct.m_tuple_ptr = tuple_ptr; Uint32 nextOp = regOperPtr.p->nextActiveOp; Uint32 prevOp = regOperPtr.p->prevActiveOp; /** * The trigger code (which is shared between detached/imediate) * check op-list to check were to read before values from * detached triggers should always read from original tuple value * from before transaction start, not from any intermediate update * * Setting the op-list has this effect */ regOperPtr.p->nextActiveOp = RNIL; regOperPtr.p->prevActiveOp = RNIL; if(tuple_ptr->m_operation_ptr_i == regOperPtr.i) { jam(); /** * Perform "real" commit */ Uint32 disk = regOperPtr.p->m_commit_disk_callback_page; set_commit_change_mask_info(regTabPtr.p, &req_struct, regOperPtr.p); checkDetachedTriggers(&req_struct, regOperPtr.p, regTabPtr.p, disk != RNIL); tuple_ptr->m_operation_ptr_i = RNIL; if (regOperPtr.p->op_type == ZDELETE) { jam(); if (get_page) { ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART); } dealloc_tuple(signal, gci_hi, gci_lo, page.p, tuple_ptr, &req_struct, regOperPtr.p, regFragPtr.p, regTabPtr.p); } else if(regOperPtr.p->op_type != ZREFRESH) { jam(); commit_operation(signal, gci_hi, gci_lo, tuple_ptr, page, regOperPtr.p, regFragPtr.p, regTabPtr.p); } else { jam(); commit_refresh(signal, gci_hi, gci_lo, tuple_ptr, page, &req_struct, regOperPtr.p, regFragPtr.p, regTabPtr.p); } } if (nextOp != RNIL) { c_operation_pool.getPtr(nextOp)->prevActiveOp = prevOp; } if (prevOp != RNIL) { c_operation_pool.getPtr(prevOp)->nextActiveOp = nextOp; } if(!regOperPtr.p->m_copy_tuple_location.isNull()) { jam(); c_undo_buffer.free_copy_tuple(®OperPtr.p->m_copy_tuple_location); } initOpConnection(regOperPtr.p); signal->theData[0] = 0; }
void Dbtup::handle_lcp_keep_commit(const Local_key* rowid, KeyReqStruct * req_struct, Operationrec * opPtrP, Fragrecord * regFragPtr, Tablerec * regTabPtr) { bool disk = false; Uint32 sizes[4]; Uint32 * copytuple = get_copy_tuple_raw(&opPtrP->m_copy_tuple_location); Tuple_header * dst = get_copy_tuple(copytuple); Tuple_header * org = req_struct->m_tuple_ptr; if (regTabPtr->need_expand(disk)) { setup_fixed_tuple_ref(req_struct, opPtrP, regTabPtr); setup_fixed_part(req_struct, opPtrP, regTabPtr); req_struct->m_tuple_ptr = dst; expand_tuple(req_struct, sizes, org, regTabPtr, disk); shrink_tuple(req_struct, sizes+2, regTabPtr, disk); } else { memcpy(dst, org, 4*regTabPtr->m_offsets[MM].m_fix_header_size); } dst->m_header_bits |= Tuple_header::COPY_TUPLE; /** * Store original row-id in copytuple[0,1] * Store next-ptr in copytuple[1,2] (set to RNIL/RNIL) * */ assert(sizeof(Local_key) == 8); memcpy(copytuple+0, rowid, sizeof(Local_key)); Local_key nil; nil.setNull(); memcpy(copytuple+2, &nil, sizeof(nil)); /** * Link it to list */ if (regFragPtr->m_lcp_keep_list_tail.isNull()) { jam(); regFragPtr->m_lcp_keep_list_head = opPtrP->m_copy_tuple_location; } else { jam(); Uint32 * tail = get_copy_tuple_raw(®FragPtr->m_lcp_keep_list_tail); Local_key nextptr; memcpy(&nextptr, tail+2, sizeof(Local_key)); ndbassert(nextptr.isNull()); nextptr = opPtrP->m_copy_tuple_location; memcpy(tail+2, &nextptr, sizeof(Local_key)); } regFragPtr->m_lcp_keep_list_tail = opPtrP->m_copy_tuple_location; /** * And finally clear m_copy_tuple_location so that it won't be freed */ opPtrP->m_copy_tuple_location.setNull(); }