db4o Blogs

db4o News

JPOX-db4o persistence

Learn about how to use db4o with JPOX (a free and fully compliant implementation of the JDO1, JDO2 specifications). Queries can be expresed using either JDOQL, SQL, or JPQL. Marcel Wirth is actively working on JDOQL support for db4o.

http://www.jpox.org/docs/1_2/developer/db4o.html

db4o thanks the JPOX team and Marcel Wirth for their continuous support!

You can find more information about JPOX here: http://www.jpox.org/

Rollback strategies

In this post Rodrigo introduced the concept of Transparent Persistence that makes developers life even easier as, once configured, db4o will take care of changed objects and make sure they are updated in the database (when the transaction gets committed) without developer assistance.This level of transparency is, of course, a welcome addition but it introduces a few questions also; for instance in the following sample (assuming it was instrumented for Transparent Persistence), 1: using (IObjectContainer db = Db4oFactory.OpenFile(ConfigureTransparentPersistence(), DatabaseFileName)) 2: { 3:     Item item = db.Query( delegate(Item candidate) { return candidate.Value == 20; } )[0]; 4: DisplayItem("Retrieved from database", item, obj => db.Ext().GetID(obj)); 5:   6: item.Value = 1; 7: db.Rollback(); 8: DisplayItem("After Rollback", item, obj => db.Ext().GetID(obj)); 9: } What should happen to item? Had the transaction committed successfully this would be ...

Read the rest of entry »

Will Web 3.0 ( Android ? ) be Peer-to-Peer ?

Yesterday I gave Google Earth a try to see what the Sky view looks like. Playing around, I decided to switch on all content layers around my area. ( 47°51'49.49"N,  11°22'41.96"E ) Happily I discovered that the virtual world around our place is not yet polluted with YouTube smog. Curious to see what a busy place looks like, I flew over to San Francisco and here is what I found: [ImageAttachment] Isn't this overvhelming already? How will you be able to find a recommended Thai restaurant on a mobile screen? Imagine every single person walking around using an Android phone, constantly sharing location, pictures, videos, going sightseeing and getting shopping hints from commercial offers. If this would work like Google Earth does today, the vertical extension of layered icons would make the phone screen shatter. What struck me when I used Google Earth was how long it took to load all the data. I have a very fast broadband connection but still it took minutes to load all these icons. When the usage of Andro ...

Read the rest of entry »

I/O Benchmarking and Simulation of Slower I/O Behaviour

I/O access times play a crucial role in the overall performance of a database.That is why we introduce two tools tomeasure the actual I/O performance of a system as seen by db4osimulate the behaviour of a slower system on a faster oneAll the code presented in this article can be found in the db4otools project / com.db4o.bench package. SVN: https://source.db4o.com/db4o/trunk/db4otools/ The code can be compiled with JDK 1.3 and higher. IoBenchmark The main class of the benchmark is com.db4o.bench.IoBenchmark.Let's have a look at it's run method to see what it does.    private void run(IoBenchmarkArgumentParser argumentParser) throws IOException {     runTargetApplication(argumentParser.objectCount());    prepareDbFile(argumentParser.objectCount());    runBenchmark(argumentParser.objectCount()); }As you can see from this code, the benchmark consists of 3 stages:Run a target application and log its I/O access patternReplay the recorded I/O operations once to prepare a database file. This ...

Read the rest of entry »

Release Notes for 7.1 development

Here is a filtered list that contains the new features and closed issues that we consider to be most relevant from the user perspective:COR-1041 Transparent Update InfrastructureCOR-1042 [.NET] Transparent Update InstrumentationCOR-1043 [.JAVA] Transparent Update InstrumentationCOR-945 Finalize Typehandler4 interface, use design as spec'd in forumsCOR-1079 Configuration interface for creating custom TypehandlersCOR-1085 Implement databaseGrowthSize configuration to reduce fragmentationCOR-1047 Ability to reply to client messages using MessageRecipientCOR-1038 Improve ObjectContainer interfaceCOR-997 Pass all test cases on AndroidCOR-990 [.NET] Build time NQ optimizationCOR-770 Defrag on 5.2 database after upgrade results in data loss -> Legacy Handler DefragCOR-939 Updates to Map cause database to grow unexpectedlyCOR-1086 SODA query returns wrong query result for .NET interfacesCOR-1097 Corrupted class index in some delete/re-add scenariosFor a complete list of all issues that were completed since db4o 7.0, ...

Read the rest of entry »

Why are you still not using db4o?

Once again our recently appointed dVP Edwin Sanchez delivers a great db4o blog post. This time it's about the reasons that may be preventing you from using db4o. It's a great approach to the subject, sometimes developers won't even consider db4o for the wrong reasons!

http://edwinstrek.blogspot.com/2008/01/6-reasons-for-not-using-db4o.html

Check Edwin's last point: Why don't you tell a friend or coworker about db4o? =)

Enjoy (thx Edwin)!

Sun buys MySQL, Oracle buys BEA

Today seems to be a good day to buy companies.

Sun buys MySQL

Oracle buys BEA

...and the day has only yet begun. Let's see what happens next.

Tim O'Reilly has commented on the price for MySQL.

Performance Guide to Tune your Application and db4o Database for Report Generation

This is a nice blog post by Edwin Sanchez which shows us which are the questions that we should ask ourselves when preparing our application to generate reports from a db4o database. Thanks Edwin!

Check it out here

Beautifying the FOOT_HILLS

In the java world a commonly accepted convention for naming constants is to use uppercase letters with words separated by underscores ("_"): MIN_DATE, MAX_DATE, etc.

In the .Net world however the official recommendation is to use PascalCase to name constants or static fields: MinDate, MaxDate, etc.

For this release we taught our converter how to translate the java convention to the .Net one so instead of the eye hurting:

1:    config.GenerateUUIDs(ConfigScope.GLOBALLY);
2: config.GenerateVersionNumbers(ConfigScope.GLOBALLY);

We now get to write:

1:    config.GenerateUUIDs(ConfigScope.Globally);
2: config.GenerateVersionNumbers(ConfigScope.Globally);

Stay beautiful!

From Transparent Activation To Transparent Persistence

Activation has been discussed in depth (no pun intended) before.

Transparent Activation is db4o's ability to defer loading an object's state until just before it's accessed for the first time.

Transparent Activation relieves programmers from keeping track of which objects must be completely available before an operation can be executed.

That's a great relief already but there's a lot more to be done in transparency land. For one thing, programmers still have to keep track of which objects are modified so they can be properly stored to the database after every operation.

Let's have a closer look at the issue in the context of a simple object model that represents the bidirectional association between users and groups:

 

 1:
2: /// <summary>
3: /// A Group has a name and a list of users that belong to it.
4: /// </summary>
5: public class Group
6: {
7: private string _name;
8: private List<User> _users = new List<User>();
9:
10: public Group(string name)
11: {
12: _name = name;
13: }
14:
15: public string Name
16: {
17: get { return _name; }
18: }
19:
20: public IEnumerable<User> Users
21: {
22: get { return _users; }
23: }
24:
25: public void AddUser(User user)
26: {
27: if (_users.Contains(user)) return;
28:
29: user.AddedToGroup(this);
30: _users.Add(user);
31: }
32:
33: public override string ToString()
34: {
35: return _name;
36: }
37: }
38:
39: /// <summary>
40: /// An User has a name and a list of group it belongs to.
41: /// </summary>
42: public class User
43: {
44: private string _name;
45: private List<Group> _groups = new List<Group>();
46:
47: public User(string name)
48: {
49: _name = name;
50: }
51:
52: public string Name
53: {
54: get { return _name; }
55: }
56:
57: public IEnumerable<Group> Groups
58: {
59: get { return _groups; }
60: }
61:
62: public override string ToString()
63: {
64: return _name;
65: }
66:
67: /// <summary>
68: /// Notifies the user it was added to a group.
69: /// </summary>
70: internal void AddedToGroup(Group g)
71: {
72: _groups.Add(g);
73: }
74: }
75:

Around that simple model we're going to build a console application that allows us to:

  1. register a new user
  2. register a new group
  3. add an user to a group
  4. list all the groups
  5. list all the users

We'll first develop the complete application without worrying too much about persistence.

For the sake of minimizing the places we have to touch as the application evolves we're going to structure it around the Model-View-Controller pattern.

We already have the model.

The view renders the console output and interacts with the user:

ConsoleView

Whenever the user asks the application to do something useful like registering a new object, the view simply gathers the data and ask the controller to execute the operation:

 

 1:
2: private void AddUserToGroup()
3: {
4: User user = SelectUser();
5: Group group = SelectGroup();
6: _controller.AddUserToGroup(user, group);
7: }
8:
9: private Group SelectGroup()
10: {
11: return ConsoleUI.SelectObject(_controller.Groups);
12: }
13:
14: private User SelectUser()
15: {
16: return ConsoleUI.SelectObject(_controller.Users);
17: }
18:

The controller keeps track of the objects and sends them the right messages at the right times:

 

 1:
2: internal class ApplicationController
3: {
4: private List<User> _users = new List<User>();
5: private List<Group> _groups = new List<Group>();
6:
7: public void AddUser(User user)
8: {
9: _users.Add(user);
10: }
11:
12: public void AddGroup(Group group)
13: {
14: _groups.Add(group);
15: }
16:
17: public void AddUserToGroup(User user, Group group)
18: {
19: group.AddUser(user);
20: }
21:
22: public IEnumerable<User> Users
23: {
24: get { return _users; }
25: }
26:
27: public IEnumerable<Group> Groups
28: {
29: get { return _groups; }
30: }
31: }
32:

Our application is ready except that it doesn't remember anything from one session to the next.

Let's now add persistence to our controller. The steps are simple:

1) move all the controller's state to IObjectContainer

 

 1:
2: internal class ApplicationController : IDisposable
3: {
4: private readonly IObjectContainer _container;
5:
6: public ApplicationController()
7: {
8: _container = Db4oFactory.OpenFile("adhoc.db4o");
9: }
10:
11: public IEnumerable<User> Users
12: {
13: get { return _container.Query<User>(); }
14: }
15:
16: public IEnumerable<Group> Groups
17: {
18: get { return _container.Query<Group>(); }
19: }
20:
21: public void Dispose()
22: {
23: _container.Dispose();
24: }
25:

2) any time objects are added or changed, IObjectContainer.Store them:

 1:
2: public void AddUser(User user)
3: {
4: _container.Store(user);
5: _container.Commit();
6: }
7:
8: public void AddGroup(Group group)
9: {
10: _container.Store(group);
11: _container.Commit();
12: }
13:

There are tricky scenarios though. Consider how to add persistence to our controller's AddUserToGroup method. We see two objects are involved in the operation:

1:
2: public void AddUserToGroup(User user, Group group)
3: {
4: group.AddUser(user);
5: }
6:

So one could assume the right persistence code would be something like:

 

1:
2: public void AddUserToGroup(User user, Group group)
3: {
4: group.AddUser(user);
5: _container.Store(user);
6: _container.Store(group);
7: _container.Commit();
8: }
9:

Which is not the case because of something called Update Depth, how deep db4o will go into the object graph persisting state. The default Update Depth is 1 which means only the immediate members of user and group get persisted in the code above. The _groups collection inside User doesn't get its members persisted just as the _users collection inside Group doesn't get its members persisted. Our changes are lost.

We know everything about the implementation of Group.AddUser so we can actually write:

 

1:
2: public void AddUserToGroup(User user, Group group)
3: {
4: group.AddUser(user);
5: _container.Ext().Store(user, 2);
6: _container.Ext().Store(group, 2);
7: _container.Commit();
8: }
9:

And that will work. The collection members will get persisted this time.

Explicitly stating the required update depth for each operation can quickly lead to code that it's very fragile to changes in the object model.

db4o provides a way to eliminate the duplication of knowledge at each call site through configuration options:

 

1:
2: IConfiguration config = Db4oFactory.NewConfiguration();
3: config.ObjectClass(typeof(User)).UpdateDepth(2);
4: config.ObjectClass(typeof(Group)).UpdateDepth(2);
5:
6: _container = Db4oFactory.OpenFile(config, "adhoc.db4o");
7:

The controller code is still dependent upon the internals of the object model but the dependency is now confined to a single place. Better.

Both approaches are still not optimal though. They violate encapsulation and incur the risk of storing much more state than it would actually be necessary - an important performance consideration.

Taking AddUserToGroup as an example we can see that the user and group objects are not changed but only the collections they hold.

We can do better.

The Unit of Work pattern as documented in the Patterns of Enterprise Application Architecture:

Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.

A simplistic but useful UnitOfWork can be implemented in a few lines of code:

 

 1:
2: public class UnitOfWork
3: {
4: /// <summary>
5: /// Adds the object to the list of affected objects in the current
6: /// unit of work.
7: /// </summary>
8: /// <param name="o">the affected object</param>
9: public static void Affected(object o)
10: {
11: List<object> current = UnitOfWork._current;
12: if (current == null) return;
13: if (current.Contains(o)) return;
14: current.Add(o);
15: }
16:
17: public delegate void Block();
18:
19: /// <summary>
20: /// Runs a block of code in the scope of a unit of work and returns the
21: /// list of affected objects.
22: /// </summary>
23: /// <param name="code"></param>
24: /// <returns></returns>
25: public static List<object> Run(Block code)
26: {
27: List<object> affectedList = new List<object>();
28: List<object> saved = _current;
29: _current = affectedList;
30: try
31: {
32: code();
33: }
34: finally
35: {
36: _current = saved;
37: }
38: return affectedList;
39: }
40:
41: [ThreadStatic] private static List<object> _current;
42: }
43:

A list of affected objects is kept in a thread local variable. The object model collaborates with the UnitOfWork class to keep the affected list current:

 

 1:
2: public class Group
3: {
4: ...
5:
6: public void AddUser(User user)
7: {
8: if (_users.Contains(user)) return;
9:
10: user.AddedToGroup(this);
11: _users.Add(user);
12:
13: UnitOfWork.Affected(_users);
14: }
15: }
16:
17: public class User
18: {
19: ...
20:
21: internal void AddedToGroup(Group g)
22: {
23: _groups.Add(g);
24:
25: UnitOfWork.Affected(_groups);
26: }
27: }
28:

 

The controller executes the operation in the scope of a UnitOfWork and gets a list of affected objects which can be easily persisted:

 

 1:
2: public void AddUserToGroup(User user, Group group)
3: {
4: List<object> affected = UnitOfWork.Run(delegate { group.AddUser(user); });
5: foreach (object o in affected)
6: {
7: _container.Store(o);
8: }
9: _container.Commit();
10: }
11:
12:

Group and User are now free to evolve independently of ApplicationController. As long as the UnitOfWork protocol is respected the application will work.

Additionally only those objects actually affected by the operation are ever persisted. A welcome performance improvement.

Can we still do better?

Quoting Dijkstra:

if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent"

Could we spend less lines?

By employing some form of metaprogramming such as bytecode engineering we could insert the right UnitOfWork calls into the model classes. We could even go an extra mile and integrate the UnitOfWork machinery with db4o transactions. In this hypothetical world, AddUserToGroup would be as simple as:

 

1:
2: public void AddUserToGroup(User user, Group group)
3: {
4: group.AddUser(user);
5: _container.Commit();
6: }
7:

 

Enter Transparent Persistence.

The latest version of db4o ships with enhancements to the Transparent Activation framework that include the ability to detect when an object retrieved from an IObjectContainer is about to be changed. It also includes a few collection classes that play well with this framework. Together with db4o's bytecode enhancement tool's (Db4oTool.exe) ability to inject the required boilerplate code we get to spend much less lines.

Let's go back to the first version of our application now, the version written with no persistence concerns and reconsider the steps of making it persistent in the light of Transparent Persistence:

1) move all the controller's state to IObjectContainer: same as before

2) configure transparent persistence:

 

 1:
2: public ApplicationController()
3: {
4: _container = Db4oFactory.OpenFile(TransparentConfiguration(), "transparent.db4o");
5: }
6:
7: private IConfiguration TransparentConfiguration()
8: {
9: IConfiguration configuration = Db4oFactory.NewConfiguration();
10: configuration.Add(new TransparentPersistenceSupport());
11: return configuration;
12: }
13:

 

3) use tranparent persistence aware collections:

 

 1:using Db4objects.Db4o.Collections;
2:
3:namespace UGMan6000.Transparent.Model
4:{
5: public class Group
6: {
7: private ArrayList4<User> _users = new ArrayList4<User>();
8:
9: ...
10: }
11:
12: public class User
13: {
14: private ArrayList4<Group> _groups = new ArrayList4<Group>();
15:
16: ...
17:
18: }
19:}

 

4) use Db4oTool to enhance the model:

PostBuild Event

Db4oTool.exe can be found in the bin directory of the db4o distribution. In the screenshot above we can see how to configure it as a Visual Studio Post-build task that enhances the generated assembly for transparent persistence (-tp) touching only the code in a specific namespace (-by-name UGMan6000.Transparent.Model).

As an exercise to the reader a quick look through Reflector's eyes should unveil how transparency is achieved.

The complete applications for each one of the design strategies discussed in this post is available here.

So what do you think?

Pages: 12NextReturn Top