Archive

Posts Tagged ‘BerkeleyDB’

Using traits to configure Berkeley JDP

March 27th, 2009

I have been using BerkeleyDBs JDP on and off a bit, just experementing with it to see how it works. BerkeleyDB is basically a B-Tree with transaction support. You store key/value pairs, both being byte arrays. JDP – Java Direct Persistence – is a layer that is built on top off this using annotations. It provides you with JPA like architecture for storing objects. Except there is no underlying SQL, just pure key lookups. This means you can’t write complex queries to select data, you will have to use code instead. But imho. this also means the complexity off what you are doing becomes more apparent.

I have fiddled around a bit with this, and I wanted to create a clean way off configuring environments. When you are using BerkeleyDB, you need to set up an Environment first:

1
Environment(File envHome, EnvironmentConfig configuration)

The EnvironmentConfig in return is set up using a setters:

1
2
3
4
EnvironmentConfig envConfig = new EnvironmentConfig();
envConfig.setTransactional(true);
envConfig.setAllowCreate(true);
envConfig.setCacheSize(1000000);

However, for Scala I wanted to use chaining to set up the environment config. The base implementation does not return this in the setters, so you can’t chain the statements. My first idea was to use implicit to convert the EnvironmentConfig to a richer version, that simply returned itself, so you could chain it.

1
2
3
4
class RichEnvConfig(val config: EnvironmentConfig) {
    def transactional() = {config.setTransactional(true); this}
    def allowCreate() = {config.setAllowCreate(true); this}
}

However I didn’t get it to work properly. I also thought about using operators to chain together traits. But then it occured to me that using traits themselves might make things clearer. So I created the following class:

1
2
3
4
5
6
7
8
object EnvConfig {
    implicit det unwrap(envCfg: EnvConfig) = envCfg.config
}
class EnvConfig {
    val config = new EnvironmentConfig()
    trait Transactional { config.setTransactional(true) }
    trait AllowCreate { config.setTransactional(true) }
}

Now I could more easily create EnvironmentConfigs and use them in code:

1
2
val config = new EnvConfig with Transactional with AllowCreate
val env = new Environment(new File("."), config)

I do however want to use the loan pattern with the Environment, as the Environment requires you to call close on it after use. So I thought instead off having a class for EnvironmentConfig, I could use have one for Environment itself, with an apply method. The Environment wouldn’t be created until it was required in apply, and using traits you could configure the Environment. Pretty happy with myself with the final solution for the Environment part:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Env(val path:File) {
    trait Transactional extends Env { config.setTransactional(true) }
    trait AllowCreate extends Env { config.setAllowCreate(true) }
 
    val config = new EnvironmentConfig()
    def apply[T](f:(Environment) => T) = {
        val env = new Environment(path, config)
        try { f(env) } finally { env.close() }
 
    }
}
 
object EnvTest extends Application {
    val env = new Env(new File(".")) with Transactional with AllowCreate
    env { e =>
        println(e)
    }
}

Some handy links to BerkeleyDB Java Edition:

Staale Programming, Scala , ,