12

I want to be up front so I will say this homework that I am about to talk about. We are suppose to do a B+ tree. I've got it most of the way there but I am having a problem when I have a node split. Specifically when the node is a non-leaf (excluding the root) and it splits I am losing my far right pointer.

For example if the tree was

                          |3 5|

           |1 2|           |4|           |5 6|

I lose the pointer to |5 6|. So when I search for those values I cannot find them or when I go to add a value that would follow that path I get a null pointer exception.

Anyway I normally would just paste my code here but, unfortunately, we have developed a problem with cheating in my school and since the program is due soon, I am sure a lot of my classmates are scouring the internet for the code. The last thing I want to happen is some jerk rip off my code.

If anyone wouldn't mind looking at the code I will gladly send it to you to check out. Once again it is in Java and is pretty lengthy.

Thanks in advance.

Here is the code. On a side node When I clear offsets and keys I use int and long MAX_VALUE so when I sort I know those cleared values will go to the end of the node. The Split class is just a dumb idea from earlier I need to fix. It consists of a node, offset, and key. Originally I was thinking that I may need to return an offset and key that wasn't in the split node. I then realized that was dumb and all I would ever need to return was the new node itself.

public void add (int key, long offset) throws IOException
{
    if (root != null) //start search of where to add the book 
    {
        SplitBucket split = add(root, key, offset); //recursive call         
        if (split != null) //root has split
        {
            long newRootOffset;
            //make new root and have it point to old root and the split node
            BookNode newRoot = new BookNode();
            newRoot.changeCurrentChildren(1);
            newRoot.setChildKey(0, split.key);
            newRoot.setChildOffset(0, root.getMyOffset());
            newRoot.setChildOffset(1, split.offset);
            newRoot.setChildOffset(2,
                root.getChildOffset(Constants.childSize -1));
            newRoot.setNode(0, root);
            newRoot.setNode(1, split.node);
            newRoot.setNode(2, root.getNode(Constants.childSize - 1));
            io.setBookNode(root.getMyOffset(), root);
            newRootOffset = io.insertNewNode(newRoot);
            io.setRoot(newRootOffset);
            root = newRoot;
        }
    }
    else //empty tree so create root and add
    {
        long rootOffset = Long.MAX_VALUE;
        root = new BookNode();
        root.setChildKey(0, key);
        root.setChildOffset(0, offset);
        root.changeCurrentChildren(1);
        root.switchLeaf(true);
        rootOffset = io.insertNewNode(root);
        io.setRoot(rootOffset);
        root.setMyOffset(rootOffset);
    }
}

/**
 * 
 * @param current current BookNode
 * @param key    Isbn to add
 * @param offset offset of Book to add
 * @return BookNode if a split occurs 
 * @throws IOException
 */
private SplitBucket add (BookNode current, int key, long offset)
        throws IOException
{
    if (current.isLeaf()) // at the bottom level
    {
        //room to add
        if (current.getCurrentChildren()  < Constants.childSize - 1)
        {
            //add the offset and key to the end of the node.
            //sort the node and rewrite to file 
            current.setChildOffset(current.getCurrentChildren(), offset);
            current.setChildKey(current.getCurrentChildren(), key);
            current.changeCurrentChildren(1);
            current.sortKeysAndOffsets();
            io.setBookNode(current.getMyOffset(), current);

            return null;
        }
        else    //not enough room must split
        {   //add offset and key to end of node and sort
            current.setChildKey(current.getCurrentChildren(), key);
            current.setChildOffset(current.getCurrentChildren(), offset);
            current.changeCurrentChildren(1);
            current.sortKeysAndOffsets();

            int start = current.getCurrentChildren() / 2;
            long newNodeOffset =Long.MAX_VALUE;
            SplitBucket bucket = new SplitBucket();
            BookNode newNode = new BookNode();

            newNode.switchLeaf(true);

            for(int i = start; i < Constants.childSize; i++)
            {
                //new node will hold the larger split values
                newNode.setChildKey(i - start, current.getChildKey(i)); 
                newNode.setChildOffset(i - start, current.getChildOffset(i));
                newNode.setNode(i - start, current.getNode(i));
                newNode.changeCurrentChildren(1);

                current.setChildKey(i, Integer.MAX_VALUE);
                current.setChildOffset(i, Long.MAX_VALUE);
                current.setNode(i, null);
                current.changeCurrentChildren(-1);
            }
            //since sorted prior to for loop all data
            //needs not to be sorted again
            newNode.sortKeysAndOffsets();
            current.sortKeysAndOffsets();
            //Transferring pre-split nodes 'next' pointer to new node
            newNode.setChildOffset(Constants.childSize, 
                current.getChildOffset(Constants.childSize));
            newNode.setNode(Constants.childSize,
                current.getNode(Constants.childSize));
            newNodeOffset = io.insertNewNode(newNode);
            newNode.setMyOffset(newNodeOffset);

            current.setChildOffset(Constants.childSize, newNodeOffset);
            current.setNode(Constants.childSize, newNode);
            io.setBookNode(current.getMyOffset(), current);

            bucket.key = newNode.getChildKey(0);
            bucket.offset = newNode.getMyOffset();
            bucket.node = newNode;

            return bucket;
        }
    }
    else //not at a leaf
    {
        int index = 0;

        //find pointer index to follow
        while (index < current.getCurrentChildren()
            && key >= current.getChildKey(index))
        {
            index++;
        }

        //recursive call 
        SplitBucket bucket = add(current.getNode(index), key, offset);            
        if(bucket != null) //split occurred
        {
            //bucket not full so add here
            if(current.getCurrentChildren() < Constants.childSize)
            {
                current.setChildKey(current.getCurrentChildren(), bucket.key);
                current.setChildOffset(current.getCurrentChildren(),
                    bucket.offset);
                current.setNode(current.getCurrentChildren(), bucket.node);
                current.changeCurrentChildren(1);
                current.sortKeysAndOffsets();

                io.setBookNode(current.getMyOffset(), current);
                bucket = null;
            }
            else        //bucket is full so split
            {
                int start = current.getCurrentChildren() / 2;
                long newNodeOffset = Long.MAX_VALUE;
                BookNode newNode = new BookNode();

                for(int i = start; i < Constants.childSize; i++) 
                {
                    //larger keys go to the new node 
                    newNode.setChildKey(i - start, current.getChildKey(i));
                    newNode.setChildOffset(i - start,
                        current.getChildOffset(i));
                    newNode.setNode(i - start, current.getNode(i));
                    newNode.changeCurrentChildren(1);

                    current.setChildKey(i, Integer.MAX_VALUE);
                    current.setChildOffset(i, Long.MAX_VALUE);
                    current.setNode(i, null);
                    current.changeCurrentChildren(-1);
                }

                if(bucket.key > newNode.getChildKey(0)) //goes in new bucket
                {
                    newNode.setChildKey(newNode.getCurrentChildren(),
                        bucket.key);
                    newNode.setChildOffset(newNode.getCurrentChildren(), 
                        bucket.offset);
                    newNode.setNode(newNode.getCurrentChildren(),
                        bucket.node);
                    newNode.changeCurrentChildren(1);
                    newNode.sortKeysAndOffsets();
                }
                else    //goes in old bucket
                {
                    current.setChildKey(current.getCurrentChildren(),
                        bucket.key);
                    current.setChildOffset(current.getCurrentChildren(), 
                        bucket.offset);
                    current.setNode(current.getCurrentChildren(),
                        bucket.node);
                    current.changeCurrentChildren(1);    
                    current.sortKeysAndOffsets();
                }
                //may not need this line and next 
                newNode.setChildOffset(newNode.getCurrentChildren(),
                    current.getChildOffset(Constants.childSize));
                newNode.setNode(newNode.getCurrentChildren(),
                    current.getNode(Constants.childSize));

                newNodeOffset = io.insertNewNode(newNode);
                newNode.setMyOffset(newNodeOffset);

                io.setBookNode(current.getMyOffset(), current);

                bucket = new SplitBucket();
                //return middle key value of split node
                bucket.key = newNode.getChildKey(
                    newNode.getCurrentChildren() /2);
                bucket.offset = newNode.getMyOffset();
                bucket.node = newNode;

                return bucket;
            }
        }
    }
    return null;
}
tcb
  • 2,745
  • 21
  • 20
Pinsickle
  • 623
  • 2
  • 10
  • 20
  • 1
    It'd probably be best to paste your node splitting code here. It wouldn't be enough for a class mate to turn in as their own, and if they made the same mistakes you did :) then at least they could learn from your question too. Besides, they'll be found out as cheaters once they are asked to write non-trivial programs during test time... – sarnold Oct 18 '11 at 23:13
  • @akappa I didn't mean it that way. Its not like I typed 1 line of code and then I went "Okay guys can you give me the other 99 lines?" People, including you, post bugs on here and ask for people to look at it. – Pinsickle Oct 18 '11 at 23:22
  • @sarnold good point there is a lot of other things (like how I translated my nodes to file and how I save my root location) that other people will still won't see paste just on my add function. Give me a second and I'll post it up. – Pinsickle Oct 18 '11 at 23:23
  • 3
    @Pinsickle: but I include the source, when I do. In this site, every question should be useful not only for the OP, but also for other people who lands here while trying to solve a similar problem. Not including the source code defeats this purpose entirely. – akappa Oct 18 '11 at 23:33
  • anyway, I'm glad you changed idea :) – akappa Oct 18 '11 at 23:34
  • 1
    True and I agree. Normally I do post the source, I'm just a little nervous to do so with this class. Our professor talked to us today about the alarming number of similar programs that have been turned in. I am sure that my professors would know that I am not a cheater as I can always explain my logic but I don't ever want someone to profit for my work. – Pinsickle Oct 18 '11 at 23:41
  • Honestly, I'd be worried if my hypothetical students turned in code that was vastly different from each others' -- many problems would naturally get the same sorts of designs by nature of what would be efficient to solve the problem. :) – sarnold Oct 19 '11 at 00:34
  • Lol true, I think what he meant was the same as in the code functions line for line the same but where one student calls the variable "x" the other calls it "y" the third calls it "z" and so on. – Pinsickle Oct 19 '11 at 00:39
  • Nothing stands out; but I'd like to suggest breaking apart your functions into smaller pieces. When you comment your `else {} ` blocks with the purpose of the `if()` test, that probably means it was pretty far away and both branches of the `if` could probably benefit from being wrapped into their own function. (And your comments provide a good start for what to _name_ the function, which is always hard to get right.) The older I get, the shorter I like my functions... – sarnold Oct 19 '11 at 00:41
  • 2
    Yes it definitely needs to be broken up. I may just stop looking for the bug for now and start breaking these into methods. Maybe when I am rearranging the code I'll stumble on the bug. I've had that happen before. – Pinsickle Oct 19 '11 at 00:45
  • Lots of copy and paste code. If you find yourself hitting ctrl+c, stop and think if you can make a method instead. – Jordan Bentley Nov 08 '11 at 01:57
  • I think the problem is in this line: newRoot.setNode(2, root.getNode(Constants.childSize - 1)); Can you debug and crosscheck whehter the above stmt does the rt thing in add() – Suraj Chandran Nov 09 '11 at 03:53
  • @sarnold-My professors always talk of easily being able to tell the difference between similar design and straight copy. One had no trouble failing each project that he deemed it true. Pulling a small section from someone else shows a break in your style. Not to mention they'll see it in the other papers and the exactness will stand out. I don't help my peers by showing them my code. However, I understand why it is essential to get help here.~ – ChiefTwoPencils Aug 19 '12 at 21:38
  • Without missing code of BookNode and SplitBucket.... truly hard find/reproduce the bug in my eclipse! ;-) – ggrandes Jan 06 '13 at 06:58

1 Answers1

1

Write a test case, or a 'main' method, for the test that fails. Then you can breakpoint & debug just that situation.

Put logging in your code, to output the important/ decisive information & things it's doing -- so you can see where it's going wrong.

Don't log uninteresting stuff -- log the API calls, which nodes are being created/ updated & which key ranges are being split. Log what really tells you what's going on.

If you don't like logging, you step thru & debug. It's not as efficient/ productive as using logging to debug & engineer your code, though.

Thomas W
  • 13,940
  • 4
  • 58
  • 76