NABoolean ex_queue::allocateAtps(CollHeap * space, atp_struct * atps, queue_index numNewAtps, Int32 atpSize, NABoolean failureIsFatal) { queue_index i; // remember that we need ATPs for this queue needsAtps_ = TRUE; // if the number of needed ATPs is not passed in, assume that all // queue entries need an ATP if (atps == NULL) { // initially try to get a whole array of ATP's rather than one // at a time We are sent back the size of the atp struct since // it also allocates space for number of tuples per criDesc. numNewAtps = size_; #pragma nowarn(1506) // warning elimination atps = allocateAtpArray( criDesc_, numNewAtps, &atpSize, space, failureIsFatal); #pragma warn(1506) // warning elimination } // check whether the caller provided the ATPs or whether we were // successful in allocating them as an array if (atps) { ex_assert(atpSize >= sizeof(atp_struct), "Invalid ATP size passed to ex_queue::allocateAtps()"); for(i = 0; i < size_; i++) { if (queue_[i].atp_ == NULL) { ex_assert(numNewAtps != 0, "There are more empty queue entries than new ATPs"); numNewAtps--; queue_[i].atp_ = atps; atps = (atp_struct *) ((char *)atps + atpSize); } } } else // Didn't get enough space to get all of them at one shot so do // it one at a time. // Allocate space for the tuples in each atp // Allocate the atp if it has not been allocated yet for(i = 0; i<size_; i++) { if (queue_[i].atp_ == NULL) { queue_[i].atp_ = allocateAtpArray(criDesc_, 1, &atpSize, space, failureIsFatal); if (!failureIsFatal && queue_[i].atp_ == NULL) return FALSE; // let user handle the failure ex_assert(queue_[i].atp_,"Memory Allocation Fatal Failure Expected but Jump Buffer does not seem to be set!"); } } atpsAllocated_ = TRUE; return TRUE; }
queue_index ex_queue::resize(ex_tcb * tcb, queue_index newSize) { queue_index sizeDelta; Space *space = tcb->getSpace(); ex_queue_entry *newQueue; queue_index newMask; Int32 queueWasFull = isFull(); NABoolean needAtps = needsAtps(); Int32 atpSize = 0; atp_struct *atps = NULL; queue_index numAllocatedAtps = 0; ex_tcb_private_state *pstates = NULL; Lng32 numAllocatedPstates = 0; Lng32 pstateLength = 0; queue_index qi; queue_index lastEntryToCopy; ex_queue_entry *oldQueue = queue_; const queue_index oldSize = size_; const queue_index oldMask = mask_; // the new size must be a power of 2, round up to the next power of 2 queue_index p2 = size_; while (p2 < newSize && p2 != 0) p2 = p2 << 1; // p2 is now a power of 2 that is >= newSize, except that // it is 0 in some unsupported cases, like size_ being 0 or newSize // being too large to be rounded up to a power of 2 newSize = p2; // can't resize to a smaller size if (newSize <= size_) return size_; sizeDelta = newSize - size_; newMask = newSize - 1; // try to allocate the needed memory first and give up if that's not // possible // allocate new array of ex_queue_entry structs newQueue = (ex_queue_entry *) (space->allocateMemory( newSize * sizeof(ex_queue_entry),FALSE)); if (newQueue == NULL) return size_; // out of memory // allocate array of ATPs if needed if (needAtps) { atps = allocateAtpArray(criDesc_, sizeDelta, &atpSize, space, FALSE); // for now, give up if it wasn't possible to allocate the ATPs in // one piece (one could try to allocate them one by one) if (atps == NULL) return size_; numAllocatedAtps = sizeDelta; } // allocate an array of pstate objects if needed if (needsPstates_) { numAllocatedPstates = sizeDelta; pstates = tcb->allocatePstates(numAllocatedPstates,pstateLength); if (pstates == NULL) { // either the TCB doesn't support the allocatePstates() // method yet (it would be a dumb thing for a TCB not to // support this AND to call the resize method) or we don't // have enough memory. Give up without changing the size. return size_; } } // at this point we have allocated everything we need, so we // should be in good shape from now on // initialize the new queue for(qi = 0; qi < newSize; qi++) { // Initialize private state pointer newQueue[qi].pstate = NULL; // initialize the public state newQueue[qi].initializeState(upDown_); // Initialize the pointer to the atp_struct newQueue[qi].atp_ = NULL; } // calculate last entry to copy (the addition here may wrap around // such that <lastEntryToCopy> is actually smaller than <head_>) lastEntryToCopy = head_ + size_; // Copy all queue entries (whether they are in use or not) over to // the new queue. Do this in such a way that the used entries move // to the new queue entry that corresponds to their index. Note // that we will start copying the used entries (if any) first, and // that those are the first entries until (but not including) the // entry where qi is equal to <tail_>. for (qi = head_; qi != lastEntryToCopy; qi++) { newQueue[qi & newMask] = queue_[qi & mask_]; } // At this point, <size_> elements of the new queue are initialized // with actual queue entries, while <sizeDelta> entries may still // need ATPs and/or pstates (if applicable). These sizeDelta entries // will be taken care of next by using the regular allocation methods // for new queues. Note that the ATPs and PSTATEs of the remaining // entries may or may not be contiguous. // reset counter that counts empty/full transitions resizePoints_ = 0; needsResize_ = FALSE; // set the data member to point to the newly allocated structures queue_ = newQueue; size_ = newSize; mask_ = newMask; NABoolean finalAllocSucceeded = TRUE; // initialize the uninitialized ATPs if required to do so if (needAtps) finalAllocSucceeded = allocateAtps(space, atps, numAllocatedAtps, atpSize, FALSE); // allocate PSTATEs for the uninitialized queue entries if this // queue needs PSTATEs if (needsPstates_ && finalAllocSucceeded) { finalAllocSucceeded = allocatePstate(tcb, pstates, numAllocatedPstates, pstateLength, FALSE); } if (finalAllocSucceeded) { // schedule the unblock subtask of the queue if the queue was full // before the resize and now is no longer full (a deadlock could // occur if we wouldn't schedule the unblock task for a full to // not full transition of a queue) if (queueWasFull) unblockSubtask_->schedule(); } else { // We failed during allocation of ATPs or PStates. Undo the switch // to the new, resized queue and restore the queue to its old state. queue_ = oldQueue; size_ = oldSize; mask_ = oldMask; } return size_; }