bool TripleIndBlockNode::rb_traverse(Context & i_ctxt, FileNode & i_fn, unsigned int i_flags, off_t i_base, off_t i_rngoff, size_t i_rngsize, BlockTraverseFunc & i_trav) { static off_t const refspan = NUMREF * NUMREF * BLKSZ; off_t startoff = max(i_rngoff, i_base); // Are we beyond the target range? if (i_base > i_rngoff + off_t(i_rngsize)) goto done; // Figure out which index we start with. for (off_t ndx = (startoff - i_base) / refspan; ndx < off_t(NUMREF); ++ndx) { off_t off = i_base + (ndx * refspan); // If we are beyond the traversal region we're done. if (off >= i_rngoff + off_t(i_rngsize)) goto done; // Find the block object to use. DoubleIndBlockNodeHandle nh; // Do we have one in the cache already? if (m_blkobj_X[ndx]) { // Yep, use it. nh = dynamic_cast<DoubleIndBlockNode *>(&*m_blkobj_X[ndx]); } else { // Nope, does it have a digest yet? if (m_blkref[ndx]) { // Does the clean cache have it? BlockNodeHandle bnh = i_ctxt.m_bncachep->lookup(m_blkref[ndx]); if (bnh) { // Yes, better be a DoubleIndBlockNode ... nh = dynamic_cast<DoubleIndBlockNode *>(&*bnh); } else { // Nope, read it from the blockstore. nh = new DoubleIndBlockNode(i_ctxt, m_blkref[ndx]); // Insert it in the clean cache. if (!(i_flags & RB_NOCACHE)) i_ctxt.m_bncachep->insert(nh); } } else if (i_flags & RB_MODIFY_X) { // Nope, create new block. nh = new DoubleIndBlockNode(); // Keep it in the dirty cache. m_blkobj_X[ndx] = nh; // Increment the block count. i_fn.blocks(i_fn.blocks() + 1); } else { // Use the zero singleton. nh = i_ctxt.m_zdinobj; // And *don't* keep it in the cache! } } // Recursively traverse ... if (nh->rb_traverse(i_ctxt, i_fn, i_flags, off, i_rngoff, i_rngsize, i_trav)) { if (i_flags & RB_MODIFY_X) { // The node is already marked dirty ... // Remove it from the clean cache. i_ctxt.m_bncachep->remove(nh->bn_blkref()); // Insert it in the dirty collection. m_blkobj_X[ndx] = nh; // We're dirty too. bn_isdirty(true); } } } done: // Return our dirty state. return bn_isdirty(); }