Example #1
0
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();
}