db4o Developer Community

db4o open source object database, native to Java and .NET
Welcome to db4o Developer Community Sign in | Join
in Search
More Search Options

Product News from the Core Team

This blog features product news right from the core developer team, once new features and functions get checked into Subversion, available as Continuous Build every 2 hours.

  • LINQ improvements.

    Hi, 

    I want to let you know that during the last few days we have made some enhancements and fixed some bugs / issues related to our LINQ implementation.

    Some of them were just annoyances that forced developers to use "not so idiomatic" styles as workarounds, some of them either resulted in crashes or wrong results being returned or even bad performance. Just in case you are curious, here are the tickets to the related issues.

    • COR-1651(bug): LINQ 'Where Not' clause against boolean field throws exception when native query optimization is enabled

    • COR-1652 (bug): DateTimeOffset field in ORDER By throws exception
    • COR-1666 (enhancement) : Support method/property chaining on LINQ queries

    • COR-1667 (enhancement) : Support simple method calls on LINQ queries 

     

    I'll use the class definition bellow to discuss these issues (Assume we have a bunch of objects of this class stored in the database):

    class Person
    {
          public string Name { get; set; }
          public bool IsMale { get; set; }
          public Guid Id { get; set; }
          public Person Parent { get; set; }


          public int GetName()
          {
              return Name;
          }

          public Person()
         {
              Id = Guid.NewGuid();
         }
    }

    The first bug (not operator on simple boolean expressions) only manifests itself in its most basic form:

    from Person p in db
    where !p.IsMale
    select p;

    The result was a crash with a InvalidOperationException inside Stack<T> class. The next issue was also related to simple boolean fields without a explicit constraint:

    from Person p in db
    where p.IsMale // no == true here.
    select p;

    but instead of throwing an exception this version would silently ignore the where clause effectively querying for all Person class objects as if the following query had been executed:

    from Person p in db
    select p;

    (note the where clause absence)

    The good news is that in latest db4o version they work as expected (revision > 13278). If you still needs to use this kind of expressions on previous versions, the workaround is to use the more verbose form:

    from Person p in db
    where p.IsMale == false  // instead of where !p.IsMale
    selec p;

    and

    from Person p in db
    where p.IsMale == true // instead of where p.IsMale
    select p;

     

    The next two issues were related to our Linq -> Soda translator. In both cases we (wrongly) concluded that the expressions were not convertible to Soda falling back to LINQ for Objects. You would still get the right results but the performance could be seriously affected depending on the actual expression. The following sample shows the failing constructs:

    from Person p in db
    where p.GetName() == "John Doe"
    selet p;

     

    from Perosn p in db
    where p.Parent.Name == "John Doe"
    select p;

    In the first one, GetName() just returns the contents of a property (or a field). The second example just happened to have two indirections (p.Parent.Name).  In both cases we used to fail to recognize these patterns as "SODA compliant" and felt back to LINQ for Objects. So, for instance, in the second sample, instead of getting something like:

    IQuery q = db.Query();
    q.Constrain(typeof(Person));
    q.Descend("_parentBackingField").Descend("_nameBackingField").Constrain("John Doe");

    foreach(var p in q.Execute())
    {
    }

    we would get something like:

    IQuery q = db.Query();
    q.Constrain(typeof(Person));

    foreach(var p in db.Execute().Where(candidate => candidate.Parent.Name == "John Doe"))
    {
    }

    which is less efficient since all objects of type Person will be retrieved.

    The last issue was not directly related to LINQ; instead it was a Soda bug regarding ordering based on value types that implements IComparable / IComparable<T>.

    So queries like (note that Id is a Guid, which implements these interfaces):

    from Person p in db
    orderby p.Id
    select p;

    would result in an exception like:

    Db4objects.Db4o.Internal.IllegalComparisonException: Exception of type 'Db4objects.Db4o.Internal.IllegalComparisonException' was thrown.
       at Db4objects.Db4o.Internal.Handlers.StandardReferenceTypeHandler.PrepareComparison(IContext context, Object source)

    It was fixed by making StandardReferenceTypeHandler aware of these interfaces.

    Well, the good notice (as you already know :) is that all of them were fixed in revision 13278, so if you faced any of these issues you may wish to check it out again :)

    As usual, you are invited to download a console application (attached to this post) that accepts a base folder as its argument and runs some tests against all db4o versions found as subdirectories under this base folder.

    We can identify all the issues discussed before in the following screen shot (run against version 7.10.96

    Issues

    And confirm that they were gone on version 7.10.99!

    ...and it is fixed in latest build

    I could not finish this post without saying that three of these issues were reported by community members. To you, our sincere thanks you!

    Best.

    Adriano

  • Give your objects a REST (interface)

    ADO.NET Data Services Framework [1], codename Astoria, a framework released with the Service Pack 1 of the .Net framework 3.5 makes it very simple to create data services that are accessible by HTTP.

    Data services can be created from any data source that implements the IQueryable<> interface (such as db4o). For updates to work however the new IUpdatable interface must also be implemented. Db4o 7.10 ships with the new Db4objects.Db4o.Data.Services assembly to provide just such an implementation.

    Let's go for a step by step example on using it.

    Here's a simple object model that we want to make accessible by HTTP:

            public class Hacker
    {
    public string Name { get; set; }
    public Team Team { get; set; }
    }

    public class Team
    {
    public string Name { get; set; }
    public List<Hacker> Hackers { get; set; }
    }

    The first step is to decorate the public types with the DataServiceKey attribute as required by Astoria:

            [DataServiceKey("Name")]
    public class Hacker
    {
    public string Name { get; set; }
    public Team Team { get; set; }
    }

    [DataServiceKey("Name")]
    public class Team
    {
    public string Name { get; set; }
    public List<Hacker> Hackers { get; set; }
    }

    The next step is to create a «Data Context». A «Data Context» is a type that binds Astoria to a specific data source and exposes IQueryable<> entry points into the data model.

    For a db4o data source we need to subclass Db4objects.Db4o.Data.Services.Db4oDataContext:

            public class TeamDataContext : Db4oDataContext
    {
    public IQueryable<Hacker> Hackers
    {
    get { return Container.AsQueryable<Hacker>(); }
    }

    public IQueryable<Team> Teams
    {
    get { return Container.AsQueryable<Team>(); }
    }

    protected override IObjectContainer OpenSession()
    {
    // ...
    }

    // ...
    }
    TeamDataContext exposes the two entry points to the object model as IQueryable<> properties: Hackers and Teams.

    It also needs to provide an IObjectContainer to service each request, a good strategy is to keep an IEmbeddedObjectContainer open throughout and just delegate the OpenSession invocation:

                protected override IObjectContainer OpenSession()
    {
    return EmbeddedObjectContainer.OpenSession();
    }

    public static IEmbeddedObjectContainer EmbeddedObjectContainer;

    As a last step we have to write an ADO.NET Data Service and bind it to our custom data context:

                public class TeamDataService : DataService<TeamDataContext>
    {
    public static void InitializeService(IDataServiceConfiguration config)
    {
    config.SetEntitySetAccessRule("*", EntitySetRights.All);
    }
    }

    And that's all that is to the server part. After we have the service running (either as part of a web application or standalone as in the provided sample) Visual Studio can be used to create a service proxy which makes remotely consuming the data as convenient as:

            var context = new TeamDataContext(new Uri("http://uri.to/service.svc"));
    var hacker = (from hacker in context.Hackers where hacker.Name == "Rodrigo").Single();


    You can find the complete sample code in the attachments.

     Have fun!

    [1] http://en.wikipedia.org/wiki/ADO.NET_Data_Services

  • db4o goes Queryable

    The LINQ framework design guidelines [1] describes the "... three means by which a type can be designed to participate in LINQ queries: implementing IEnumerable<> ..., implementing IQueryable<>, or by defining the Query Pattern on the type".

    For db4o we chose the Query Pattern implementation because only a subset of the available LINQ operators could be reasonably supported. By implementing the pattern for the operators we support any code that references an unsupported operator automatically falls back to LINQ to Objects.

    Yes, implementing IQueryable<> [2] used to be that slightly more complicated approach recommended when most LINQ operators were supported by the provider. Things have changed and IQueryable<> is now being used by APIs everywhere as the lowest common denominator for optimizing LINQ providers.

    Which is why we decided to make LINQ to db4o support the IQueryable interface as well.

    Just as with LINQ to db4o, it's very easy to use and completely integrated:

            using Db4objects.Db4o.Linq;

    // ...

    IObjectContainer container = Db4oEmbedded.OpenFile("HR.db4o");
    IQueryable<Person> query = container.AsQueryable<Person>();


    Et voila, you can pass `query` around as an IQueryable/IQueryable<Person> reference to every API which is dynamically manipulating a LINQ query using the IQueryable interface or the Queryable extension methods.

    Shall a scalar method be called on this IQueryable or shall it be iterated over, the underlying implementation will rewrite the query expression tree into an optimized LINQ to db4o query. For the unsupported operators the query would still fallback to LINQ to Objects, meaning that all Queryable methods can be used without distinction.

    We'll see in a next post how we've leveraged our IQueryable implementation to support an API which actually demands it.

    [1] http://blogs.msdn.com/mirceat/archive/2008/03/13/linq-framework-design-guidelines.aspx
    [2] http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx

     

    Note: if you want to check out a demos that use these new features see this page

            using Db4objects.Db4o.Linq;

    // ...

    IObjectContainer container = Db4oEmbedded.OpenFile("HR.db4o");
    IQueryable<Person> query = container.AsQueryable<Person>();


    Et voila, you can pass `query` around as an IQueryable/IQueryable<Person> reference to every API which is dynamically manipulating a LINQ query using the IQueryable interface or the Queryable extension methods.

    Shall a scalar method be called on this IQueryable or shall it be iterated over, the underlying implementation will rewrite the query expression tree into an optimized LINQ to db4o query. For the unsupported operators the query would still fallback to LINQ to Objects, meaning that all Queryable methods can be used without distinction.

    We'll see in a next post how we've leveraged our IQueryable implementation to support an API which actually demands it.

    [1] http://blogs.msdn.com/mirceat/archive/2008/03/13/linq-framework-design-guidelines.aspx
    [2] http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx

    Note: if you want to check out a demo using this new feature see this page
  • In the search of silver

    Hi!

    If you develop for .Net (and even if you don't :) the odds are high that you've already heard about Microsoft Silverlight, a platform for developing RIA style applications.

    In this post I'd like to share some of our experiences while working on adding support for this platform to db4o, but before we move on, I'd like to stress some points:

    • The goal of this post is to describe the way we plan to add Silverlight support but we cant guarantee that we'll be able to stick to these plans. Also, we assume that readers have a good understanding of the related technologies (db4o, .Net, Silverlight)
    • Even though we're committed to this goal, as of today, Silverlight is not an officially supported platform.
    • All decisions are being taken based on the assumption that db4o most common usage scenario in this platform will be to store objects locally
      (RIA) hence we're focusing on embedded mode. Of course, we are a community driven project so this can change in the future.
    • Last but not least, current code assumes Silverlight Beta 3 (it might work on Silverlight 2 but that hasn't been checked).

    That said, let's take a look on how the porting process looks like (strikethrough activities have been completed already):

    1. Feature set / limitations and possible fixes
    2. Understand the required changes / Port the selected projects
    3. Update/extend development tools like Sharpen
    4. Port the tests
    5. Update documentation
    6. Write samples
    7. Integrate into the build
    8. Publish Silverlight artifacts to web site

    Feature set / Limitations
     
    The first step was relatively simple: given the tight constrains imposed by Silverlight we just picked a doable set of features. For the initial support we decided
    to concentrate our efforts in embedded mode, leaving some features out.
     
    Also, while working on porting db4o to run on Silverlight we assembled a list of limitations and possible improvements:
    • By default Silverlight apps have a quota of 1.0 Mb of disk space. Using the right APIs it's possible to ask for more (through a user consent dialog). It would be nice if db4o could use this API to increase its quota once it detects that it is running out of space.

    • Only public fields are allowed (AFAIK, Silverlight doesn't support reflection over private fields). That means that fields need to be declared as public to be "storable".

    • db4o requires some additional configuration (this is the most severe limitation IMHO).

    • Client / Server mode: Silverlight doesn't allow direct socket connections so, at least with db4o's current implementation, it's not possible to support CS mode. We could make the communication channel pluggable and, maybe, use "REST" instead of TCP/IP but this would require more investigation.
      [edited on Jun / 23] Some days ago, Ashish Shetty, a kind program manager at Silverlight team just alerted me that this sentence may be misleading and that actually Silverlight support client sockets (with some port restrictions). The main point is that, at least for now, we'll not pursue adding client / server support on Silverlight platform [/edited]

    • Native queries / Linq: Since both technologies rely on Mono.Cecil and friends and these assemblies were not ported to Silverlight it's not possible to support them for now (anyway, we saw some good news regarding Mono.Cecil in this forum thread).
    We are planing to investigate whether the Db4oTool can be used to instrument Silverlight assemblies and optimize native queries at compile time. If we manage to instrument Silverlight assemblies Db4oTool could be used to turn storable types into "self reflectors" through interface injection.
     
     
    Understanding required changes
     
    Understanding the changes required to successfully compile for Silverlight consisted mainly in getting the list of unsupported interfaces/classes/methods and adapting the code accordingly. The biggest changes were due to the lack of some I/O classes as well non generic collections, restrictions on assembly loading and a tighter security model. These constraints were the cause of most of the compilation errors we found.
     
    For the I/O classes db4o is using an implementation from Michael Sync (which, by the way, was really helpful in the porting process and is the kind developer willing to spend time and help; hey guy, thank you very much!). Technically speaking, Michael wrote a db4o storage based on .Net IsolatedStorage model.
     
    The lack of non generic classes was trickier to solve than we expected; since most of db4o C# code is converted from java (and from some historical reasons we convert from java 1.2 codebase which by the way is converted from java 1.5 code :) most of the collections used were the non-generic ones. This forced us to review the code and, when possible, use the generic version. In some cases the simplest solution was to introduce a non-generic collection (based on its generic counter-part) mimicking the native, non-generic, missing collection.
     
    The last restriction in this list was the most frustrating one. db4o relies heavily on being able to load assemblies referenced by persisted objects and Silverlight security model doesn't allow arbitrary assemblies to be loaded explicitly. Actually (AFAIK) it is possible to load assemblies only if you specify a fully qualified assembly name, including its version. The problem with this approach is that db4o doesn't know about the assembly version (to be more precise db4o strips assembly versions away when storing objects). One possible solution would be to try to iterate over the already loaded assemblies and grab the reference from this list instead of trying to reload "already loaded" assemblies, but this brought us another frustration: this same security model disallows iterating over this list also (the decision to always load assemblies instead of applying the process described above was taken based on the fact that the performance impact of calling Assembly.Load() on "already loaded" assemblies is barely perceptible).
     
    The solution we found (at least for now) relies on the fact that most applications know, at compile time, the assemblies declaring storable types. On Silverlight, every time db4o needs to get an assembly reference it'll raise a TypeReference.AssemblyResolve (static) event and will allow the application to resolve and return the required reference. The included sample shows a possible implementation for this. We are thinking on having a new class encapsulate the details of this pattern but we decided to postpone the introduction of this class until we better understand the restrictions and get some feedback on the design.
     
    [edited on Jun / 23] Ashish Shetty, just pointed me to this page and explained that using this API we could workaround the assembly loading issue. We are gonne to investigate it soon.[/edited]
     
    Current Status
     
    As of today the following projects compile successfully under the Silverlight platform (see Db4o-Silverlight-2008.sln):
    • Core (Db4objects.Db4o)
    • Tests (Db4objects.Db4o.Tests)
      • No CS tests
      • No Migration tests
      • No Interoperability tests
      • No Linq / NQ tests
    • Optional (Db4objects.Db4o.Optional)
    • Db4oUnit
    • Db4oUnit.Extensions
    Unfortunately successful compilation has very little to do with a software being usable / stable. Right now we have a subset of a full db4o test suite running against this platform. As we manage to run more of these tests we are sure that new issues will be found (for instance this one was caught when we started to run the first tests). 
     
     
    Required changes to Applications
     
    In order to make the discussion more practical I've written a very simple CRUD Silverlight application. Keep in mind that this is my first Silverlight application :), so please give me some feedback if you see that something smells bad :)
     
    Before you continue reading I suggest you download the application source code and take a look at it (bellow you can see a screenshot)
     
     
    Through this really innovative user interface (seriously, it's a break through :) it's possible to add a new person by entering its first name/last name and then pressing the "add" button. To query, fill in the fields you want to query on (first name and/or last name) and press "query" button. To delete an object, select it in the listbox and press "delete". Thats it :)
     
    The most important aspect of this sample lies in the following lines:
     
            #region Assembly.Load() issue workaround

            private static readonly IDictionary<string, Assembly> _assemblyCache = new Dictionary<string, Assembly>();
            static App()
            {
                //_assemblyCache[AssemblyNameFor(typeof(Queue<>))] = typeof(Queue<>).Assembly;
                //_assemblyCache[AssemblyNameFor(typeof(List<>))] = typeof(List<>).Assembly;
                _assemblyCache[AssemblyNameFor(typeof(Person))] = typeof(Person).Assembly;
                _assemblyCache[AssemblyNameFor(typeof(Db4oFactory))] = typeof(Db4oFactory).Assembly;
               
                TypeReference.AssemblyResolve += (sender, args) =>  args.Assembly = _assemblyCache[args.Name];
            }

            #endregion
     
    and
     
            private static IEmbeddedConfiguration Config()
            {
                IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();
                config.File.Storage = new IsolatedStorageStorage();
                return config;
            }
     
    in app.xaml.cs file.
     
    Basically it just populates a dictionary mapping from an assembly name to the respective assembly reference and registers for TypeReference.AssemblyResolve events. Once this event gets raised we just look for the assembly name in our map. This is required as a workaround on assembly loading constraints.
     
    Note that any type referenced by your model (stored objects) should have its assembly listed in this map otherwise bad things will happen to you :) Jokes apart, if you fail to list an assembly in this map db4o will handle types defined in this assembly as generic classes, i.e, classes that don't have the original class definition, and this will not work as expected in most cases. Since this is hardly the desired behavior, a possible improvement would be to throw an exception (inside AssemblyResolve event if the requested assembly could not be found in the map) instead of returning null.
     
    Also note that we declared the Person's fields as public otherwise we'd get exceptions at runtime. We discussed these limitations on the "limitations" topic above.
     
     
    Wrapping it up
     
    In order to support Silverlight we're required to introduce changes into db4o (including some deprecated classes/methods that were wiped out). For developers, the most important requirements are to register for TypeReference.AssemblyResolve event in order to return assembly references and to use IsolatedStorageStorage, as shown in the sample.
    Silverlight support is on the way, but even though we had a steady progress (it can be tracked through COR-1611 issue) we do have some homework to do before we can declare it officially supported. 
     
    Based on our initial list of tasks we can see that currently we are working on porting / adapting the tests. As the next steps we're considering the following:
    1. Integrate Silverlight into the build (mainly run the tests in our continuous build)
    2. Finish porting tests
    3. Investigate performance issues
    4. Update documentation
    5. Write samples
    6. Publish Silverlight artifacts to the website
    Of course, community involvement is a strong force that'll help us decide how much effort we shall put into this. So, if you are learning or already develop for the Silverlight platform we invite you to grab the db4o sources from our svn repository, try it with your projects and provide as much feedback as possible (reporting any issues, questions, suggestions, ideas, etc).
     
    Finally, fell free to drop me a line at adriano at db4o dot com if you need any help to get started.
     
     [edited on Jun / 23] As I said, some days after publishing this post, Ashish Shetty got in touch to alert me about some issues; I'd like to thank you for taking the time :)[/edited]
     
    Best.
     
    Adriano
  • Release Notes - 7.10 Development Release

    db4o version 7.10 is out and here is the list of modifications, improvements and bug fixes that you will find in it:

  • COR-1642 - Ensure proper exception handling in Eclipse plugin
  • COR-1633 - Blog about Silverlight
  • COR-1631 - schema evolution not working correctly for client server mode.
  • COR-1630 - Attributes are not being respected by the configuration
  • COR-1629 - Class filter configuration UI for Eclipse instrumentation plugin
  • COR-1628 - Get Db4objects.Db4o.Tests projects compiling under Silverlight
  • COR-1627 - Provide instrumentation step in Eclipse plugin
  • COR-1626 - Adding a new indexed value typed field to an existing persisted class triggers NPE
  • COR-1621 - merge type handlers branch
  • COR-1620 - PropertyChangedEventHandler causes InvalidSlotException when used with ArrayList4
  • COR-1617 - Add Db4o core Silverlight project to build
  • COR-1616 - Extend Java HashSet for TA
  • COR-1615 - Extend Java TreeSet for TA
  • COR-1613 - remove ExtObjectContainer#collections and all related code
  • COR-1612 - Bring trunk as close as possible to silverlight version
  • COR-1608 - Review MsgD implementations to make sure exceptions are transmitted to the client
  • COR-1605 - [Java] running TA instrumented AllTestsDb4ounitJdk5
  • COR-1604 - Activation decision is being taken upon field type instead of actual type
  • COR-1603 - Extend Java Stack for TA
  • COR-1602 - Extend Java HashTable for TA
  • COR-1599 - Synchronize KnownClassesRepository access in GenericReflector against database lock
  • COR-1598 - Diagnostics warns about missing field indexes on class-only queries
  • COR-1597 - db4o_osgi with rcp app problem
  • COR-1596 - Allow to specify dedicated target storage for backup
  • COR-1591 - migration support for TreeSet - from the old translator based format to the new type handler based one
  • COR-1590 - define expected behavior for multiple TypeHandlers (including InstantiatingTypeHandlers) in a class hierarchy
  • COR-1588 - Migration support for .net enums (broken after type handler api changes)
  • COR-1587 - .net enums should be indexable
  • COR-1584 - Remove dependency on Thread.SetData() / GetData() to enable progress on Silverlight support.
  • COR-1579 - move from FirstClass/SecondClass terminology to ReferenceType/ValueType terminology
  • COR-1578 - Detach FieldHandler from TypeHandler and ClassMetadata hierarchies and assign responsibilities
  • COR-1577 - PlainObjectHandler should not be embedded and should not have to manage identity explicitly
  • COR-1576 - Defragmenting an encrypted file throws OutOfMemoryException
  • COR-1573 - Separate ClassMetadata from TypeHandler
  • COR-1572 - Extend Java HashMap for TA
  • COR-1560 - Db4oTool doesn't instrument constructors for transparent persistence
  • COR-1539 - Readding a deleted object from a different client changes database ID in embedded mode
  • COR-1531 - Enum upgrade from 7.7 to 7.8 causes loss of information
  • COR-1527 - Type Handlers - Design discussion
  • COR-1514 - Implement/register TypeHandler for TreeSet
  • COR-1481 - TypeReference class fails with 'open' generic types
  • COR-1357 - Db4o-2008.sln does not compile in the distribution
  • COR-1336 - Emmit a warning when instrumenting classes with non private fields.
  • COR-1136 - Defrag an in-memory database
  • COR-864 - When lockDatabaseFile() is configured to be false, database files should not be locked.
  • COR-715 - DatabaseFileLockedException when database file folder doesn't exist
  • Automagically enable db4o Transparent Persistence for Java via Eclipse

    Transparent Activation/Transparent Persistence (TA/TP) significantly simplifies handling of deep object graphs in db4o based applications. The flip side is that this mechanism requires your persistent domain classes to provide appropriate API hooks. These hooks can be implemented manually, alternatively the tedious task of generating this boilerplate code can be delegated to the db4o bytecode instrumentation framework. So far there have been two options to trigger instrumentation: Programmatically, or through a custom Ant task. Now there is a third option, if you happen to be developing with Eclipse: Install the db4o instrumentation plugin and have your classes instrumented in-place and on-the-fly, taking advantage of Eclipse's incremental building features.

    This project is still in its early incubation phase - we're counting on your feedback to get everything right before we elevate it to official distribution. Until then, you can grab the latest state from the update site located within the svn project:

    http://source.db4o.com/db4o/trunk/db4oplugin/db4oplugin/update-site

    Note that this plugin requires Eclipse version 3.4.0 or later.

    After installing the plugin, you will find a new context menu entry for Java projects, offering to add a db4o nature. This nature will install an instrumentation builder that gets triggered by all changes to .class files. A custom project properties page will allow you to specify which classes you want to instrument, based on a combination of package selection and regular expressions matching fully qualified class names. There is a (rudimentary) custom log view to keep you informed about all instrumentation activities. More detailed information is provided in the Eclipse integrated help included with the plugin.

    Attachment: db4oplugin.small.png (94361 bytes)


    This project is work in progress. We recommend to NOT use it in a production environment at this point in time, but we'd like to encourage you to try it and share bug reports, feature requests and other suggestions for improvement in the developer forum.

    The next missing major feature probably is support for instrumentation of jar files. (Currently the builder only handles raw class files.) This is already covered by the instrumentation core framework, so the plugin implementation main concern is what a decent UI for this feature should look like. For further pending tasks/issues, see the todo list in the project and our issue tracker (related tasks are tagged 'eclipse_plugin'). Any feedback is welcome.

    If you feel adventurous enough to take a stab at the source code, note that the plugin is written in Scala, so you'll probably want to install the Scala plugin before checking out the project. (If you've ever considered doing an Eclipse plugin with Scala, just give it a try, Scala blends in surprising well with PDE development.)

  • Transparent Persistence for Java Collections

    In our latest development build we provide a first implementation of Transparent Activation and Transparent Persistence for standard Java collections.

    In case you don't know what these terms mean:
    Transparent Activation (TA) loads members of persistent objects lazily when they are accessed.
    Transparent Persistence (TP) flags objects as dirty when their members are modified, so these objects are stored upon the next commit.

    If you decide to work with TA and TP, you will not need any ObjectContainer#store() calls to update objects and no
    ObjectContainer#activate() calls to activate object graphs. db4o does all the work nicely for you: transparently.

    In order for TA and TP to work, persistent classes need to implement the Activatable interface.

    Our Ant enhancer task com.db4o.enhance.Db4oEnhancerAntTask can add the necessary code to your persistent classes, as demonstrated in the Ant script further down in this posting.

    Because we could not change the implementation of the standard Java collections we decided to derive classes
    from them and to add the Activatable code in these derived classes.

    The com.db4o.collections package now contains the following implementations:
    ActivatableArrayList
    ActivatableHashMap
    ActivatableHashSet
    ActivatableHashtable
    ActivatableLinkedList
    ActivatableStack
    ActivatableTreeSet

    The above is a complete list of all the collections that we support so far. Internally we have overridden all public methods. In these methods we call #activate() and then delegate to the parent methods. Please note that we have only added support for JDK 5 methods, because of backward compatibility issues of our build system. If you use JDK 6 methods you will run into problems.

    In your code you do not have to use our derived collection classes. Our Ant enhancer task com.db4o.enhance.Db4oEnhancerAntTask will exchange all collection constructor calls in your code to create Activatable collections instead.

    Let's create a small sample project that uses Transparent Persistence to check things out:

    package com.db4o.sample;
    
    import java.util.*;
    
    public class Team {
    	
    	private String name;
    	
    	private List pilots;
    	
    	public Team(String name){
    		this.name = name;
    	}
    	
    	public void addPilot(Pilot pilot){
    		if(pilots == null){
    			pilots = new ArrayList();
    		}
    		pilots.add(pilot);
    	}
    	
    	@Override
    	public String toString() {
    		String str = "Team " + name;
    		if(pilots != null){
    			str += " with pilots: ";
    			for (Pilot p : pilots){
    				str += p + " ";
    			}
    		}
    		return str;
    	}
    	
    	public String getName(){
    		return name;
    	}
    
    }
    
    
    package com.db4o.sample;
    
    public class Pilot {
    	
    	private String name;
    	
    	public Pilot(String name){
    		this.name = name;
    	}
    	
    	@Override
    	public String toString() {
    		return name;
    	}
    	
    }
    
    package com.db4o.sample;
    
    import java.io.*;
    
    import com.db4o.*;
    import com.db4o.config.*;
    import com.db4o.cs.*;
    import com.db4o.cs.config.*;
    import com.db4o.query.*;
    import com.db4o.ta.*;
    
    public class Program {
    	
    	private static String FILE = "tp.db4o";
    	
    	private static int PORT = 4444;
    	
    	private ObjectContainer objectContainer;
    	
    	private ObjectServer objectServer;
    	
    	public static void main(String[] args) {
    		new Program().run(); 
    	}
    	
    	public void run() {
    		deleteDatabaseFile();  // to make the sample rerunnable
    		openObjectContainer();
    		storeTeam();
    		close();
    		openObjectContainer();
    		addPilots();
    		close();
    		openObjectContainer();
    		printTeams();
    		close();
    	}
    
    	private void deleteDatabaseFile() {
    		new File(FILE).delete();
    	}
    	
    	private void printTeams() {
    		ObjectSet objectSet = objectContainer.query(Team.class);
    		while(objectSet.hasNext()){
    			System.out.println(objectSet.next());
    		}
    	}
    
    	private void openObjectContainer(){
    		openEmbeddedObjectContainer();
    		// openClientServerObjectContainer();  
    	}
    	
    	private void openEmbeddedObjectContainer(){
    		EmbeddedConfiguration embeddedConfiguration = Db4oEmbedded.newConfiguration();
    		embeddedConfiguration.common().add(new TransparentPersistenceSupport());
    		objectContainer = Db4oEmbedded.openFile(embeddedConfiguration, FILE);
    	}
    	
    	private void openClientServerObjectContainer(){
    		ServerConfiguration serverConfiguration = Db4oClientServer.newServerConfiguration();
    		serverConfiguration.common().add(new TransparentPersistenceSupport());
    		objectServer = Db4oClientServer.openServer(serverConfiguration, FILE, PORT);
    		objectServer.grantAccess("db4o", "db4o");
    		
    		ClientConfiguration clientConfiguration = Db4oClientServer.newClientConfiguration();
    		clientConfiguration.common().add(new TransparentPersistenceSupport());
    		objectContainer = Db4oClientServer.openClient(clientConfiguration, "localhost", PORT, "db4o", "db4o");
    	}
    	
    	private void storeTeam(){
    		Team team = new Team("Ferrari");
    		objectContainer.store(team);
    	}
    	
    	private void addPilots() {
    		Team team = queryTeamByName("Ferrari");
    		team.addPilot(new Pilot("Massa"));
    		team.addPilot(new Pilot("Raikkonen"));
    	}
    	
    	private Team queryTeamByName(final String name){
    		ObjectSet objectSet = objectContainer.query(new Predicate() {
    			@Override
    			public boolean match(Team team) {
    				return team.getName().equals(name);
    			}
    		});
    		return objectSet.next();
    	}
    
    	private void close(){
    		objectContainer.close();
    		if(objectServer != null){
    			objectServer.close();
    		}
    	}
    	
    }
    

    We also need an Ant script that enhances our program for Transparent Persistence:

    <project name="db4o.TP.sample" basedir="." default="run">
       
    <property name="dir.src" value="${basedir}/src" />
       
    <property name="dir.bin" value="${basedir}/bin" />

       <path id="project.classpath">
          
    <fileset dir="lib">
             
    <include name="**/*.jar"/>
          
    </fileset>
       
    </path>

       <taskdef name="db4o-enhance" 
          classname="com.db4o.enhance.Db4oEnhancerAntTask"
          
    classpathref="project.classpath" />

       <target name="compile">
          
    <mkdir dir="${dir.bin}" />
          
    <javac srcdir="${dir.src}" destdir="${dir.bin}" failonerror="true">
             
    <classpath refid="project.classpath" />
          
    </javac>
       
    </target>

       <target name="enhance" depends="compile">
          
    <db4o-enhance classtargetdir="${dir.bin}" ta="true" nq="true" collections="true">
             
    <classpath refid="project.classpath" />
             
    <sources dir="${dir.bin}">
                
    <include name="**/*.class" />
             
    </sources>
          
    </db4o-enhance>
       
    </target>

       <target name="run" depends="enhance">
          
    <java classname="com.db4o.sample.Program" failonerror="true">
             
    <classpath>
                
    <pathelement path="${dir.bin}" />
                
    <path refid="project.classpath" />
             
    </classpath>
          
    </java>
       
    </target>

    </project>

    If you want to try this project out yourself all you need is the db4o-7.[version].[iteration].[build]-all-java5.jar in the lib folder of your project. For your convenience I have attached a full Eclipse project with the above sources and with the db4o-all.jar to this posting. If you now run the Ant script, it prints out:
    Team Ferrari with pilots: Massa Raikkonen

    Can you see the interesting part of this small project?
    The #addPilots() method never has to call ObjectContainer#store(). Because the ArrayList in Team.pilots is exchanged with an ActivatableArrayList and because TransparentPersistenceSupport is added to the db4o configuration, it is sufficient to add the pilots to the list and they will be stored in the automatic commit of the close() operation. Isn't that nice and easy?

    You are invited to experiment with db4o Transparent Persistence and to tell us about your experiences in the db4o forum.

    Enjoy!

  • Modified CascadeOnDelete Behaviour

    db4o offers a configuration option to cascade delete on to child objects when the parent object is deleted.

    To use it, you can configure db4o as follows:

    // embedded mode
    EmbeddedConfiguration config = Db4oEmbedded.newConfiguration();
    config.common().objectClass(MyClass.class).cascadeOnDelete(true);
    Db4oEmbedded.openFile(config, "my.db4o");

    // Client/Server mode
    ServerConfiguration config = Db4oClientServer.newServerConfiguration();
    config.common().objectClass(MyClass.class).cascadeOnDelete(true);
    Db4oClientServer.openServer(config, "my.db4o", PORT);

    In the past we deleted child objects also when a reference to a child object was removed. In the latest builds we have changed this behaviour to delete only when a true delete happens.

    In the process of writing more test cases we also discovered a serious bug: If ObjectContainer#store() was called multiple times for an object, it could happen that a delete on a child object was triggered, although there still was a reference to this child object. This has been fixed.

    For all users of cascaded delete we recommend updating to the latest stable and development builds. They are online now with the following build numbers:
    7.4.86.12797
    7.9.86.12784

  • Release Notes - 7.9 Development Release

    Hi!

    It's a time for a new release again and here is a list of changes, bug fixes and improvements that we are putting into it.

    There were quite a lot of fixes for Object Manager Enterprise (Visual Studio version):

  • OMN-160 - Blog about latest OMN fixes / changes
  • OMN-158 - Changes to objects in detail view may be lost
  • OMN-157 - Field updates may be lost
  • OMN-153 - Installing OME messes up VS environment
  • OMN-152 - Changes to any element in a array/collection were applied to the first one.
  • OMN-150 - Changes "disappear" while editing objects in MasterView
  • OMN-149 - OME Install fails in UNC environment
  • OMN-148 - Exception when editing field value in master view
  • OMN-147 - Exception when editing field constrain values
  • OMN-143 - Unable to connect to a remote server
  • OMN-139 - It's not possible to save enum / struct fields
  • OMN-133 - 'Master' and 'Detail' views not synchronized upon object deletion
  • OMN-125 - Support Nullable primitive types
  • OMN-105 - Status bar message should go away when not logged in
  • OMN-100 - OMN should ship with latest production release (7.2)
  • OMN-72 - Status message in the toolbar should not be a button
  • OMN-42 - DataGrids should stretch the column width to accomodate all content if there is enough space on the screen

  • And in db4o core we also did lots of improvements, but we also accomplished another great job - cleaned our Jira and closed the issues that were already fixed long time ago, but were still "hanging" open in Jira. Hope it will help our users to see a clearer picture of the db4o current and future state.

    Note, that the report below combines the issues actually fixed for 7.9 and those that were closed as they were fixed before:


  • COR-1567 - Support boxing within predicates
  • COR-1559 - Defragment breaks null field index entries
  • COR-1558 - db4o should throw when a configuration is reused
  • COR-1556 - Db4o should throw when the user requests a non indexable field to be indexed
  • COR-1555 - BigInteger/BigDecimal are not indexable
  • COR-1554 - ClassCastException when storing a class containing an array member
  • COR-1553 - Full framework integration for TA/TP collection instrumentation
  • COR-1552 - pair to review iUpdatable for LINQ
  • COR-1551 - Updating objects with UUIDs turned on may result in OutOfMemoryException
  • COR-1550 - Missing signature for ObjectServer#OpenClient(IClientConfiguration)
  • COR-1549 - Remove Platform4#isDb4oClass
  • COR-1547 - [.net] TA instrumentation - check how constructors are being enhanced
  • COR-1546 - When Server and Client are in same Visual Studio Instance then transaparent activation does not work with db4o 7.8
  • COR-1544 - TA may instrument field access in constructor before init is called
  • COR-1543 - Descending query into an untyped List member produces InvalidIdException
  • COR-1541 - Defragment will migrate class index even if the class doesn't have one anymore
  • COR-1540 - Temporary inconsistent state in networking C/S updates from ObjectReference#writeUpdate()
  • COR-1538 - After Migrating old enum implememtation to new enum implementation and deleting all old enum entries does not delete enums.
  • COR-1537 - TA/TP ArrayList Tracer Bullet
  • COR-1536 - Member queries into generic LinkedList are not working
  • COR-1529 - Extend Java ArrayList for TA
  • COR-1528 - Configuration option callConstructors(true) does not work.
  • COR-1525 - BigSet should be threadsafe
  • COR-1523 - Problem with querying uncommitted BigSet
  • COR-1522 - Support for java.math.BigDecimal
  • COR-1521 - ReflectField for unavailable class always returns nullable type for primitives regardless of the original field type being nullable
  • COR-1520 - Add API doc to BigSet explaining that it is not thread-safe
  • COR-1518 - Typehandler for BigInteger/BigDecimal
  • COR-1513 - Always throw appropriate exception when opening database files with a marshallerfamily version newer than the current library
  • COR-1511 - Introduce marker interface for persisted internal classes
  • COR-1501 - Nullable Datetime on .NET is not retrieved as null
  • COR-1486 - DB4OTool Crash optimizing Native Querys on Generic Class
  • COR-1453 - LRU2QCache implementation (com.db4o.internal.caching.Cache)
  • COR-1446 - Constraining a field to null doesn't use the field index
  • COR-1437 - Better caching strategy for the linq optimizer
  • COR-1361 - Get() method of IStoredField returns null when field type has changed.
  • COR-1358 - MemoryIoAdapter does not use GrowBy value
  • COR-1356 - TransparentActivationSupport is not documented in API docs
  • COR-1352 - Extensive collection tests with .NET generic collections
  • COR-1314 - db4o unable to store raw Object's (throws in com.db4o.internal.ClassMetadata.forObject)
  • COR-1310 - When updating enum arrays, the "old" array copy remains
  • COR-1277 - Review and test ListTypeHandler implementations
  • COR-1249 - Extra dll in \db4o-7.3\bin\net-3.5 for db4o-7.3.38.10577-net35.msi
  • COR-1242 - 'null' value in field of object when using List instead of ArrayList
  • COR-1175 - Investigate HashMapUpdateFileSizeTestCase failures
  • COR-1172 - Plugin to downgrade java 5 code to java 1.1 code (varargs and foreach)
  • COR-1171 - Defragment support for System.Collections.Generic.List
  • COR-1163 - project missing in Db4objects.Db4o.Tests-CF-2005.sln for db4o-7.2.30.10211-net2.msi
  • COR-1150 - Db4oTool should search for necessary assemblies in the working directory
  • COR-1142 - Optimized LINQ implementation for CompactFramework through bytecode enhancement
  • COR-1130 - Support nullable types in arrays
  • COR-1087 - Race condition with weak reference collector thread on database close
  • COR-1061 - objectField.queryEvaluation is not used
  • COR-1008 - External CallBack objectOnDelete() invoke when stroring new Objects
  • COR-1005 - [TA] Several configurations of TransparentActivationSupport results in IllegalStateException while binding the Activator
  • COR-969 - Db4objects.Db4o.Internal.Handlers.MultidimensionalArrayHandler.AllElements(Db4objects.Db4o.Reflect.IReflectArray, object)' hides inherited member 'Db4objects.Db4o.Internal.Handlers.ArrayHandler.AllElements(Db4objects.Db4o.Reflect.IReflectArray, object)'.
  • COR-891 - CascadeOnDelete should only influence delete handling
  • COR-884 - byte array storage format was changed for untyped references and needs updater
  • COR-777 - Collection Class returned from db4o database not able to reference objects via its key anymore
  • COR-767 - IllegalStateException in Client/Server mode (communication is not thread-save)
  • COR-759 - Server-side config choices should not appear on client connection API (and the reverse)
  • COR-752 - Add Bundle-ActivationPolicy: lazy header to db4o-osgi
  • COR-740 - Pointer slots should be smaller for configured blockSize() values
  • COR-731 - Defrag on db causes indexOutOFbounds exception
  • COR-730 - [db4occ.stable] Different behavior between OptimizeNativeQueries(true) and OptimizeNativeQueries(false)
  • COR-711 - File locking thread race condition
  • COR-707 - FastCollections: Simple Pluggable TypeHandler4
  • COR-561 - com.db4o.db4ounit.jre11.AllTests fail on cc win
  • COR-560 - Map implementation delivers unexpected results in C/S setup
  • COR-542 - Callbacks are ignored on nested classes
  • COR-495 - Translate AvailableClassFilter to .NET
  • COR-492 - Exceptions in callbacks must bubble up
  • COR-429 - Create Test that checks compatability between Java and .NET database files
  • COR-384 - Exponential increase in size of DB when using Maps
  • COR-378 - Update tuning, reread object slot only when needed
  • COR-345 - Spec out Modularization Possibilities
  • COR-298 - Implement a LINQ to db4o
  • COR-294 - Implement .NET/Java type translation in terms of Aliases
  • COR-154 - Mock all IO for testing (run regression tests on mocked IO objects that simulate failures)
  • COR-135 - UTF-8, UTF-16, pluggable string encoding
  • COR-117 - Db4o.configure().objectClass(..).objectField("bogusField") should cause error
  • COR-53 - Rename com.db4o.Debug
  • COR-49 - commit, rollback, and delete(?) should execute syncronously
  • COR-32 - Enum handling assumes callConstructors(false)
  • COR-18 - Multiple sorts in SODA queries is broken
  • OMN Improvements

    Since the announcement that Object Manager Enterprise would be added to our open source offerings we take the time and a lot of improvements were made: bugs were fixed, code were rewritten and we started to add tests (incipient, but at least we started).

    Take a look in our issue tracking system and you'll see that a bunch of bugs were fixed (and some new were found/added) (for instance, we fixed some bugs that caused value types to not be saved in some scenarios).

    If you are using OMN (Object Manager Enterprise .Net) , please,  report any issues you find. Also, we encourage you to vote in JIRA for the issues that are important to you, so we have more information about what's important to our users and this can help in deciding what to do next.

    Last, but not least, we are aware about of other existing OMN issues and we are working hard (within our constrains) to make it better.

    Anyway, Db4o is an open source project, so feel free to grab the source code, take a look and if you feel like wanting to contribute, feel free to send your opinion, ideas, comments, patches, etc. :)

    Best

    Adriano

  • New kid on the block - Array of Nullables

    Hi.

    Have you ever used these funny types with a question mark in DotNet?

    Well, they are called Nullable types and were introduced to provide the ability to set value types to "null", enabling a more natural integration between some datasets (such relational databases) and DotNet world. For instance, relational databases supports the concept of null fields even for integers. By the other hand .Net integers are value types which doesn't have such concept (someone said object/relational type mismatch?). (Just for the records, the syntax type? identifier is a C# shorthand for the full declaration: Nullable<type> identifier).

    As I commented out in this post, at Db4o, we are continually pursuing better platform compliance (be it related to idioms, type system support, etc.) so some time ago we improved support for nullable types like in the following example

    class TestNullableContainer
    {
        private int? _value;
    }

    The next logical step was to extend this support to arrays, allowing Db4o to store arrays of nullables. In previous versions (< 7.9) we stored the array successfully but there were no way to retrieve it (instead an exception would be thrown). The problem was that in prior versions we loose the information about "nullableness", i.e, arrays such as int? []items were stored as if they were the "non nullable" counterpart (int []items) and even though we would successfully retrieve them from database .Net would just throw when trying to assign the just read object to the respective field (something like: int? []items = new int[] {1, 2, 3}).

    Unfortunately extending nullable support to arrays of nullables proved to be trickier than we expected but after some code rewrite, we finally got it working (please, note that we still have some work to do regarding some not so common array usages scenarios).

    To make it easier to spot the differences I've included a sample application that allows you to select a specific Db4o version (starting with 7.1) and run a piece of code against it (it is an adaptation of my last post sample app). You can test it with any number of different Db4o versions and compare the outcome of each one. To use this application simply compile the 2 projects (Db4oTestRunner and NullableArraysTest), then fire Db4oTestRunner and select NullableArraysTest assembly and finally click on "run" button (of course, you can write your own tests :).

    Since our goal is to continue improving platform compliance, we'd like to know which improvements regarding platform compliance you'd like to see.

    Please, go, download the test application (either  from the attached TestNullableArrays.zip file or get it through svn: svn co https://source.db4o.com/db4o/trunk/sandbox/Adriano/Blogs/), and play with it.

    Best

    Adriano

  • Native Support for Java BigInteger/BigDecimal

    Do you have much more money than you can fit into a long? Or do you like splitting hairs to fractions that cannot be accurately measured with double values? Then chances are that you are not happy with the primitive numeric types Java provides, and you'll have to resort to BigInteger/BigDecimal. Now you can rely on dedicated db4o support for applications requiring this level of magnitude and/or accuracy.

    Well, actually db4o has supported BI/BD instances already in a way - they are objects, so db4o could store and retrieve them. But there were quite some show stoppers:
    • These classes rely on transient field setup in the constructor. Worse, the internal representation has changed over time: db4o would require (sometimes JDK version specific) configuration to be able to reinstantiate these objects to a consistent state.
    • db4o would store instances of these classes as full object graphs: A BigDecimal contains a BigInteger which contains a byte array, plus some more white noise at all object graph levels. This graph would faithfully be persisted into the database file and it would have to be read and reconstructed on access.
    • Querying would not be reasonably applicable to instances of these classes: The best you could hope for was "query by example" semantics - which are bound to fail in the presence of "state relevant" transient fields.

    Enter a type handler that makes BI/BD almost look like primitive types from a db4o point of view: You lose "object identity" for those values (they are effectively handled as value types like int/float), in turn you gain much faster marshall/unmarshall times and query capabilities, including indexing. Instead of persisting full object graphs, the primitive representations provided by BigInteger#toByteArray() and BigDecimal#toString() are used for the marshalling process. In an artificial benchmark, this type handler shows 2-3x better marshall/unmarshall performance for BI, 3-4x for BD. Queries into BI/BD now just work like queries into int/float, and they can take advantage of field indices (potentially speeding up queries by multiple orders of magnitude).

    BI/BD support is packaged with the db4o-optional module/jar, enabling it is as simple as typing

    config.add(new BigMathSupport());

    Please take a look and report any issues or suggestions for improvement you may encounter. This code (with the abstract class com.db4o.internal.handlers.BigNumberTypeHandler containing the bulk of the implementation) may also serve as a blueprint for custom type handler implementations for "primitive-like" objects. Please note that work on the type handler API is still in progress - we still discourage custom use of the current API in production environments, but we wholeheartedly encourage all feedback from experimental use that may help us to further improve it.

  • Release Notes - 7.8 Development Release

    The following Jira bugs and issues were fixed for db4o-7.8 Development Release:

  • COR-1517 - [.NET] Support for System.Array
  • COR-1509 - Exception when browsing through the objects
  • COR-1508 - Defrag fails with IndexOutOfRangeException
  • COR-1507 - ExtObjectContainer#knownClasses throws an exception
  • COR-1506 - Review Transparent Activation for subclasses
  • COR-1504 - WeakReferenceCollector spawns new threads when weak reference collection is already in progress
  • COR-1503 - Create an example and blog about db4o use with PowerShell
  • COR-1502 - Typehandlers for CollectionBase and DictionaryBase
  • COR-1499 - BigSet storage gets progressively slower in doubly-linked list
  • COR-1494 - Batch store operation (specially for TP optimization)
  • COR-1491 - Flush dirty TP objects before query execution
  • COR-1488 - Empty iterator doesn't implement #reset()
  • COR-1487 - Constraint is set incorrectly in ObjectContainer#queryByExample()
  • COR-1484 - Client/Server queries over objects that were enhanced for Tranparent Persistence may produce inconsistent results
  • COR-1483 - Provide support for integrating db4o with Powershell
  • COR-1479 - [java] include CS docs in the generated javadocs
  • COR-1478 - [.NET] include CS docs in the generated help
  • COR-1477 - Fix Bin access inconsistency for timer file lock
  • COR-1476 - Soda Query does not return right results for enum set to 0
  • COR-1475 - Fix differente exception handling in Java/.Net callbacks
  • COR-1474 - Fix *HandlerUpdateTestCase trying to set null on primitive fields
  • COR-1471 - implement complete 2q algorithm and benchmark against LRUCache
  • COR-1470 - "Unexpected token: 'Token(Kind: GenericQualifier, Value: '`')'" thrown on "System.Data.Listeners`1+Func`2"
  • COR-1468 - Db4oTool crashes when loading some PDBs
  • COR-1467 - IoAdapter with cache for jdk11
  • COR-1465 - remove seek from the IoAdapter interface and always pass the position as an argument to read and write
  • COR-1461 - Optimize LRU2QCache: benchmark different internal representations (ArrayList versus simple and double linked lists)
  • COR-1460 - db4ounit improvement: take advantage of varargs
  • COR-1458 - benchmark com.db4o.internal.caching.Cache based IoAdapter against CachedIoAdapter using PolePosition
  • COR-1457 - IoAdapter that works with com.db4o.internal.caching.Cache
  • COR-1456 - Throw exception on reentrant db4o call from callback
  • COR-1455 - remove catch alls from reflection layer
  • COR-1453 - LRU2QCache implementation (com.db4o.internal.caching.Cache)
  • COR-1451 - garbage collection breaks transparent persistence
  • COR-1450 - DatabaseClosedException from weak reference collector in .NET C/S mode with TA
  • COR-1449 - Reduce memory consumption of OR join against single indexed field
  • COR-1448 - .NET Reflector that emits code dynamically to bypass reflection
  • COR-1433 - Stack overflow when Hashtable4 does IncreaseSize() due to Reposition(HashtableIntEntry entry) being recursive
  • COR-1387 - Add tests to guarantee interoperability between .Net/.Net.CF databases
  • COR-1303 - Investigate LRU cache for BTree nodes
  • COR-1280 - Transparent Update Won't Work On Iterative Updates
  • COR-1045 - [.Net] Handle enums as valuetypes (i.e, in the same way as integers)
  • COR-1032 - [.NET] Generic Collections
  • COR-1028 - Updating an object containing enum adds new entry in the database.
  • COR-942 - Db4objects.Db4o.Tests.CLI2.TA.NullableTypeActivationTestCase.TestDepthN fails on .NET CF 2.0
  • COR-886 - Db4o is not storing .NET generic collections if the generic parameters are not primitive
  • COR-813 - GenCol: HashSet
  • COR-806 - GenCol: CollectionBase
  • COR-726 - [CS] test failures
  • COR-723 - Get Compact Framework test to pass
  • COR-215 - BTrees: Remove processed constraints so they do not spend time in the SODA processor
  • COR-69 - .net Generic collections are not translated and are stored as this
  • COR-5 - Split Localmode from Client/Server
  • Object Manager Enterprise Now Free To All Developers

    I have great news for db4o developers - starting from version 7.8 db4o release will be completed with a new product: Object Manager Enterprise (OME). Those of you, who were following db4o events, should remember that OME is not a new product. It was first released a bit more than a year ago, but was only available for commercial users.This policy was reviewed after db4o acquisition by Versant and a new accent was put on simplicity and value to the community. It was agreed that a tool providing a graphical interface to db4o database is undoubtedly important both to new and experienced developers and open-source customers, therefore should be a part of the product and free for all db4o users.

    Object Manager Enterprise - what is it?

    Database browsing tool is not a new concept for db4o. Earlier we provided a java-based standalone application (Object Manager) for browsing db4o databases, however it was not equally convenient for .NET users and without integration into the development environment did not seem to satisfy developer needs. The new product - Object Manager Enterprise is a plug-in for your development environment (Visual Studio 2005/2008 for .NET users and Eclipse for Java users). OME allows you to browse your db4o database in a graphical interface. With OME you can always check which objects were stored and how the database structure looks like. Additional benefit - you can check the correctness of your queries by comparing the query result with the view in OME.

    The screenshots below show a simple database view in Eclipse and Visual Studio 2008 OME versions:

    OME

    Eclipse: browsing Pilot class

    OME

    Visual Studio 2008: Pilot class

     

    In addition to simple browsing OME provides the following features:

    • Graphical query design (drag&drop)
    • Database object modification and deletion
    • Simultaneous database view while debugging in client/server mode
    • Indexing
    • Backup
    • Defragment
    • Access to db4o developer website within the IDE and updates download.

    Installation and Documentation

    OME installation is included in db4o distribution.

    If you are using Java version you will find OME distro in /ome folder of the db4o installation package.  In order to install it, unzip ObjectManagerEnterprise-Java-[version].zip into any folder and use it from within Eclipse as a local update site (use Eclipse documentation for the exact steps). Alternatively you can copy the contents of contents of the 'plugins' and 'features' folders from the unzipped folder to the corresponding subfolders in the root folder of your Eclipse installation.

    After OME is installed you might need to go to Windows/Open Perspective/Other within Eclipse and switch to OME perspective.

    Visual Studio users can opt to install OME as part of db4o installation (using msi). If the OME installation was initially skipped, it can be started separately from the shortcut in the db4objects Start menu:

    OME

    If you have downloaded db4o .NET release as a zip archive, you will find OME installation in the distribution omn-2005 or omn-2008 folder.

    For further documentation please refer to db4o tutorial.

    Don't forget to share your opinion on this new product with us. Bug reports and improvement suggestions can be filed in our Jira system: project code is OMN (OME .NET) for .NET version and OMJ (OME Java)  for java version.

  • New caches for db4o

    Looking for ways to make db4o faster, we recently invested some work into better caching. We found a nice paper here and decided to implement a LRU/2Q cache for db4o. Our new cache implementations can now be found in the classes LRU2QCache, LRU2QXCache and LRUCache. Feel free to use them anywhere the GPL allows you to.

    As the best testing ground for the new caches we identified our IoAdapters. Driven by the requirement to make the caching layer pluggable, we first refactored IoAdapters from their old factory-and-implementation-in-a-single-class approach to a clean factory concept. The roots of the new class hierarchy:
    Storage - a factory class that knows how to open a Bin
    Bin - a representation of a container for storage of data
    If you are interested in details of the implementation, it's probably easiest if you browse the sources and open the type hierarchy for Storage and Bin from your favourite IDE. The existing old IoAdapter interface still continues to work, wrapped by an IoAdapterStorage.

    After we had the caching and a corrected Storage interface, we wrote a new CachingStorage that makes use of the caches. Benchmarking the new cache implementations against our old specialized CachingIoAdapter we found that the old cache was already very good. It took us quite a bit of tuning work to reach the same speed again, but we managed. Accordingly we could safely replace the old CachingIoAdapter with the new CachingStorage in the default db4o configuration.

    Here are three of the most common configuration setups that you may be interested in for everyday use of db4o:

    (1) Setting up db4o with a different cache page size and page count

    final int cachePageCount = 128;
    final int cachePageSize = 4096;
    Storage cachedStorage = new CachingStorage(new FileStorage(), cachePageCount, cachePageSize){
    // By overriding the newCache method you can plug in a different cache
        @Override
        protected Cache4 newCache() {
            return CacheFactory.new2QXCache(cachePageCount);
        }
    };
    
    // opening an embedded session
    EmbeddedConfiguration embeddedConfiguration = Db4oEmbedded.newConfiguration();
    FileConfiguration fileConfiguration = embeddedConfiguration.file();
    fileConfiguration.storage(cachedStorage);
    Db4oEmbedded.openFile(embeddedConfiguration, "myEmbeddedDb.db4o");
    
    // opening a server for a client/server session
    ServerConfiguration serverConfiguration = Db4oClientServer.newServerConfiguration();
    FileConfiguration fileConfiguration = serverConfiguration.file();
    fileConfiguration.storage(cachedStorage);
    Db4oClientServer.openServer(serverConfiguration, "myServerDb.db4o", PORT);
    

    (2) Using db4o as a fast in-memory database

    //opening an embedded session
    EmbeddedConfiguration embeddedConfiguration = Db4oEmbedded.newConfiguration();
    FileConfiguration fileConfiguration = embeddedConfiguration.file();
    fileConfiguration.storage(new MemoryStorage());
    Db4oEmbedded.openFile(embeddedConfiguration, "myEmbeddedDb.db4o");
    
    // opening a server for a client/server session
    ServerConfiguration serverConfiguration = Db4oClientServer.newServerConfiguration();
    FileConfiguration fileConfiguration = serverConfiguration.file();
    fileConfiguration.storage(new MemoryStorage());
    Db4oClientServer.openServer(serverConfiguration, "myServerDb.db4o", PORT);
    

    (3) Using the NonFlushingStorage for highly improved db4o speed at the risk of corrupted database files in case of abnormal system failures

    Storage nonFlushingStorage = new NonFlushingStorage(new CachingStorage(new FileStorage()));
    
    // opening an embedded session
    EmbeddedConfiguration embeddedConfiguration = Db4oEmbedded.newConfiguration();
    FileConfiguration fileConfiguration = embeddedConfiguration.file();
    fileConfiguration.storage(nonFlushingStorage);
    Db4oEmbedded.openFile(embeddedConfiguration, "myEmbeddedDb.db4o");
    
    // opening a server for a client/server session
    ServerConfiguration serverConfiguration = Db4oClientServer.newServerConfiguration();
    FileConfiguration fileConfiguration = serverConfiguration.file();
    fileConfiguration.storage(nonFlushingStorage);
    Db4oClientServer.openServer(serverConfiguration, "myServerDb.db4o", PORT);
    

    In case you have missed Adriano's article, the above also demonstrates how the new configuration interface is intended to be used.

    Now that we had a new good working caching architecture, we thought about further places where to use it. We came up with the idea to cache BTree nodes directly. Since these nodes are used for class indexes and for field indexes we expected improved performance for repetitive queries.

    To get caching of BTree nodes to work, we implemented a new CacheablePersistentBase class to override some of the default behaviour of PersistentBase and derived BTreeNode from this new class.

    After we had all up and running smoothely we compared the performance of different setups with the Poleposition benchmark. We could indeed see much faster queries if queries were executed in the same way a second time. Therefore we decided to leave this new second level cache in db4o as the default with a size of 30.

    The size of the new node cache is also configurable as follows:

    // opening an embedded session
    EmbeddedConfiguration embeddedConfiguration = Db4oEmbedded.newConfiguration();
    embeddedConfiguration.cache().slotCacheSize(64);
    Db4oEmbedded.openFile(embeddedConfiguration, "myEmbeddedDb.db4o");
    
    //opening a server for a client/server session
    ServerConfiguration serverConfiguration = Db4oClientServer.newServerConfiguration();
    serverConfiguration.cache().slotCacheSize(64);
    Db4oClientServer.openServer(serverConfiguration, "myServerDb.db4o", PORT);
    

    Do not expect wonders from using the new caches but please do play with all parameters, if you want to get the maximum speed out of db4o. The best cache settings will depend a lot on your individual usecase. We would be very happy if you would tell us about your experiences from testing out the new caches. Thanks in advance!

    Enjoy!

More Posts Next page »

This Blog

Syndication RSS Feeds

News

Get the latest features every 2 hours with the Continuous Build!