protected long load( TransactionManager xact_manager, Heap heap, boolean createConglom, RowLocationRetRowSource rowSource) throws StandardException { long num_rows_loaded = 0; if (SanityManager.DEBUG) { SanityManager.ASSERT( open_conglom == null, "load expects container handle to be closed on entry."); } // The individual rows that are inserted are not logged. To use a // logged interface, use insert. RESOLVE: do we want to allow client // to use the load interface even for logged insert? int mode = (ContainerHandle.MODE_FORUPDATE | ContainerHandle.MODE_UNLOGGED); // If the container is being created in the same operation, don't log // page allocation. if (createConglom) mode |= ContainerHandle.MODE_CREATE_UNLOGGED; OpenConglomerate open_conglom = new OpenHeap(); if (open_conglom.init( (ContainerHandle) null, heap, heap.format_ids, heap.collation_ids, xact_manager, xact_manager.getRawStoreXact(), false, mode, TransactionController.MODE_TABLE, xact_manager .getRawStoreXact() .newLockingPolicy( LockingPolicy.MODE_CONTAINER, TransactionController.ISOLATION_SERIALIZABLE, true), (DynamicCompiledOpenConglomInfo) null) == null) { throw StandardException.newException( SQLState.HEAP_CONTAINER_NOT_FOUND, new Long(heap.getId().getContainerId())); } this.init(open_conglom); // For bulk loading, we always use only brand new page because the row // insertion itself is not logged. We cannot pollute pages with // pre-existing data with unlogged rows because nobody is going to wipe // out these rows if the transaction rolls back. We are counting on // the allocation page rollback to obliterate these rows if the // transaction fails, or, in the CREAT_UNLOGGED case, the whole // container to be removed. Page page = open_conglom.getContainer().addPage(); boolean callbackWithRowLocation = rowSource.needsRowLocation(); RecordHandle rh; HeapRowLocation rowlocation; if (callbackWithRowLocation) rowlocation = new HeapRowLocation(); else rowlocation = null; FormatableBitSet validColumns = rowSource.getValidColumns(); try { // get the next row and its valid columns from the rowSource DataValueDescriptor[] row; while ((row = rowSource.getNextRowFromRowSource()) != null) { num_rows_loaded++; if (SanityManager.DEBUG) { // Make sure valid columns are in the list. The RowUtil // call is too expensive to make in a released system for // every insert. int invalidColumn = RowUtil.columnOutOfRange(row, validColumns, heap.format_ids.length); if (invalidColumn >= 0) { throw (StandardException.newException( SQLState.HEAP_TEMPLATE_MISMATCH, new Long(invalidColumn), new Long(heap.format_ids.length))); } } // Insert it onto this page as long as it can fit more rows. if ((rh = page.insert( row, validColumns, Page.INSERT_DEFAULT, AccessFactoryGlobals.HEAP_OVERFLOW_THRESHOLD)) == null) { // Insert faied, row did not fit. Get a new page. page.unlatch(); page = null; page = open_conglom.getContainer().addPage(); // RESOLVE (mikem) - no long rows yet so the following code // will get an exception from the raw store for a row that // does not fit on a page. // // Multi-thread considerations aside, the raw store will // guarantee that any size row will fit on an empty page. rh = page.insert( row, validColumns, Page.INSERT_OVERFLOW, AccessFactoryGlobals.HEAP_OVERFLOW_THRESHOLD); } // Else, the row fit. If we are expected to call back with the // row location, do so. All the while keep the page latched // and go for the next row. if (callbackWithRowLocation) { rowlocation.setFrom(rh); rowSource.rowLocation(rowlocation); } } page.unlatch(); page = null; // Done with the container, now we need to flush it to disk since // it is unlogged. if (!heap.isTemporary()) open_conglom.getContainer().flushContainer(); } finally { // If an error happened here, don't bother flushing the // container since the changes should be rolled back anyhow. close(); } return (num_rows_loaded); }
/** * Insert a new row into the heap. * * <p>Overflow policy: The current heap access method implements an algorithm that optimizes for * fetch efficiency vs. space efficiency. A row will not be over flowed unless it is bigger than a * page. If it is bigger than a page then it's initial part will be placed on a page and then * subsequent parts will be overflowed to other pages. * * <p> * * @return The record handle of the inserted row. * @param row The row to insert. * @exception StandardException Standard exception policy. */ private RecordHandle doInsert(DataValueDescriptor[] row) throws StandardException { Page page = null; byte insert_mode; RecordHandle rh; if (SanityManager.DEBUG) { Heap heap = (Heap) open_conglom.getConglomerate(); // Make sure valid columns are in the list. The RowUtil // call is too expensive to make in a released system for // every insert. int invalidColumn = RowUtil.columnOutOfRange(row, null, heap.format_ids.length); if (invalidColumn >= 0) { throw (StandardException.newException( SQLState.HEAP_TEMPLATE_MISMATCH, new Long(invalidColumn), new Long(heap.format_ids.length))); } } // Get the last page that was returned for insert or the last page // that was allocated. page = open_conglom.getContainer().getPageForInsert(0); if (page != null) { // if there are 0 rows on the page allow the insert to overflow. insert_mode = (page.recordCount() == 0) ? Page.INSERT_OVERFLOW : Page.INSERT_DEFAULT; // Check to see if there is enough space on the page // for the row. rh = page.insert(row, null, insert_mode, AccessFactoryGlobals.HEAP_OVERFLOW_THRESHOLD); page.unlatch(); page = null; // If we have found a page with enough space for the row, // insert it and release exclusive access to the page. if (rh != null) { return rh; } } // If the last inserted page is now full, or RawStore have // forgotten what it was, or the row cannot fit on the last // inserted page, try to have rawStore get a relatively unfilled // page. page = open_conglom.getContainer().getPageForInsert(ContainerHandle.GET_PAGE_UNFILLED); if (page != null) { // Do the insert all over again hoping that it will fit into // this page, and if not, allocate a new page. // if there are 0 rows on the page allow the insert to overflow. insert_mode = (page.recordCount() == 0) ? Page.INSERT_OVERFLOW : Page.INSERT_DEFAULT; rh = page.insert(row, null, insert_mode, AccessFactoryGlobals.HEAP_OVERFLOW_THRESHOLD); page.unlatch(); page = null; // If we have found a page with enough space for the row, // insert it and release exclusive access to the page. if (rh != null) { return rh; } } page = open_conglom.getContainer().addPage(); // At this point with long rows the raw store will guarantee // that any size row will fit on an empty page. rh = page.insert(row, null, Page.INSERT_OVERFLOW, AccessFactoryGlobals.HEAP_OVERFLOW_THRESHOLD); page.unlatch(); page = null; if (SanityManager.DEBUG) { // a null will only be returned if this page is not empty SanityManager.ASSERT(rh != null); } return rh; }