3

I am using db4o 8.0. The db4odatabase file size is 21MB. The database has following Objects in it.

User : There is 1 user in db.
PostedMessage : There are 10000 postedMessages in db.

I delete all 10000 PostedMessages. Then I try to defragment the db4o database. Following code is used for Defragmentation.

private void processDefrag() {
    try {
        String dbpath = "D:\\db4oDatabase";

        IdMapping mapping = new InMemoryIdMapping();
        //new DatabaseIdMapping(dbpath); //use this if heap overflows

        DefragmentConfig config = new DefragmentConfig(dbpath, dbpath+".bak", mapping);
        config.storedClassFilter(new AvailableClassFilter());
        config.forceBackupDelete(false);
        config.objectCommitFrequency(1000);
        Defragment.defrag(config);
        System.out.println("Defrag completed");

    } catch (IOException ex) {
        ex.printStackTrace();
    }
}

My expectation is that the db4oDatabase file size will go back to 21 Kb. And the db4oDatabase will still contain the 1 User object in it. However, after running the above code, the db4odatabase becomes completely empty. Why is it happening like that?

How can I avoid losing the other objects which were not deleted (in this case the 1 User object)? What is the right way of doing defragmentation on db4o database?

  • I assume you will be defragmenting a much larger database as 21 MB of disk can cost as little as 0.2 cents. i.e. it wouldn't be worth it. – Peter Lawrey Sep 10 '12 at 16:07
  • Does this code have access to the `User` class? I.e., if you call [`Class.forName("com.mypackage.User");`](http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#forName%28java.lang.String%29) in this code with your `User` class' FQCN, will it throw an exception? – Brian Sep 10 '12 at 16:29
  • @Peter: I am using 21 MB database during development i.e. just for testing purposes. During production, it is expected to reach more than 3 to 4 GB, or even larger. – You Help Me Help You Sep 10 '12 at 16:43
  • @Brian: My code has access to the User class. It would not throw an exception. – You Help Me Help You Sep 10 '12 at 16:44
  • That's different. 4 GB can cost 40 cents. ;) – Peter Lawrey Sep 10 '12 at 16:46
  • lol... @Peter: unnecessarily larger database can hamper the query performance. – You Help Me Help You Sep 10 '12 at 16:52
  • @Peter : Can you spot what am I doing wrong in the code that is causing deletion of the Objects in db4oDatabase? Or what am I not configuring because of which this unintended behavior is happening? – You Help Me Help You Sep 10 '12 at 16:53
  • @YouHelpMeHelpYou Okay, so you really trying to save memory. The smaller the database, the less memory it needs to cache all of it. I won't mention how much 4 GB of memory costs. ;) Sorry, I can't see what you are doing wrong. – Peter Lawrey Sep 10 '12 at 17:01
  • How can I poke cl-r or Gamlor on SO? Who usually have good answers for db4o questions? – You Help Me Help You Sep 10 '12 at 17:42
  • @Brian : It seems that my code is not seeing all the StoredClasses in the database. Because of which, it deletes them. – You Help Me Help You Sep 10 '12 at 18:52
  • @YouHelpMeHelpYou Put the code from your comment into your question instead of the comments section so it's easy to read. – Brian Sep 10 '12 at 19:01

3 Answers3

2

If it's not accepting the class because it can't find it, you might try writing a StoredClassFilter of your own that just accepts all StoredClass objects.

public class AcceptAllClassFilter implements StoredClassFilter {

    @Override
    public boolean accept(StoredClass storedClass) {
        return true;
    }
}

Then:

config.storedClassFilter(new AcceptAllClassFilter());

This will work unless the defrag process just deletes everything without a StoredClass automatically. If this is the case, we may need to figure out why the User class doesn't have a corresponding StoredClass instance for the container.

Brian
  • 17,079
  • 6
  • 43
  • 66
0
public static void printStoredClasses(ObjectContainer db) {
    StoredClass[] storedClasses = db.ext().storedClasses();
    for (StoredClass sc : storedClasses) {
        try {        
            Class<?> c = Class.forName(sc.getName());
            DebugMessagePrinter.print(c.getName());
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
    }
}

I used the above method to print the stored classes. And as Brian guessed it, for some reason, it did not print the User and PostedMessage class names. That implies that it is not able to see those classes in the db4o database file.

0

Finally, with the help of Brian's AcceptAllFilter class, I could successfully defrag the db4oDatabase file. The size reduced to 12MB from 21 MB. The working method is shown below.

private void process() {
    try {
        String dbpath = "D:\\db4oDatabase";
        printStoredClassNames(dbpath);

        IdMapping mapping = new InMemoryIdMapping();
        //new DatabaseIdMapping(dbpath); //use this if heap overflows

        DefragmentConfig config = new DefragmentConfig(dbpath, dbpath+".bak2", mapping);
        config.storedClassFilter(new AcceptAllClassFilter());
        config.forceBackupDelete(false);
        config.objectCommitFrequency(1000);
        config.db4oConfig().add(new UuidSupport());
        Defragment.defrag(config);
        System.out.println("Defrag completed" + t.s());

    } catch (IOException ex) {
        ex.printStackTrace();
    }
}

Btw, the defragmentation does not seem to be doing its job at its best. After deleting 10000 PostedMessage objects, the database contained only the 1 User Object. I would expect the database file size to be in KBs.

But, as they say, something is better than nothing. With this some amount of success, I will keep the search for better defragmeentation on. if I happen to get better results, I will post em here.