Question

I am having trouble getting replication to function completely between two db4o databases. I have followed many tutorials and my code seems to be on par with them (well obviously not though). The output suggests that the ReplicationSession is detecting changes but it isn't replicating the changes in the other database.

private ReflectiveDatabase()
{
    openDb();
    providerA = new Db4oEmbeddedReplicationProvider(hostContainer);
    providerB = new Db4oEmbeddedReplicationProvider(clientContainer);

    //Start a new ReplicationSession with event for replacing newest object on conflict.
    replication = Replication.begin(providerA, providerB,
    new ReplicationEventListener() {
        @Override
        public  void onReplicate(ReplicationEvent replicationEvent) {
            if (replicationEvent.isConflict()) {
                ObjectState stateDesktop = replicationEvent.stateInProviderA();
                ObjectState stateMobile = replicationEvent.stateInProviderB();

                if (stateDesktop.modificationDate() >= stateMobile.modificationDate()) {
                    replicationEvent.overrideWith(stateDesktop);
                } else {
                    replicationEvent.overrideWith(stateMobile);
                }
            }
        }
    });   
}

public EmbeddedConfiguration configure()
{
    EmbeddedConfiguration configuration = Db4oEmbedded.newConfiguration();
    configuration.file().generateUUIDs(ConfigScope.GLOBALLY);
    configuration.file().generateCommitTimestamps(true);
    return configuration;
}

public void openDb()
{
    // try to connect to the host
    if(hostContainer != null) hostContainer.close();

    try
    {
        hostContainer = Db4oEmbedded.openFile(configure(), "local1.db4o");
    }
    catch (com.db4o.ext.Db4oIOException e)
    {
        ...
    }

    // try to connect to the client
    if(clientContainer != null) 
    {
        clientContainer.close();
    }

    try
    {
        clientContainer = Db4oEmbedded.openFile(configure(), "local2.db4o");
    }
    catch (com.db4o.ext.Db4oIOException e)
    {
        ...
    }
}

And here is the actual syncing that I have been running from a timer every 8s

public void syncDatabases()
{        
    // First get the changes of the two replication-partners
    ObjectSet<Object> changesOnHost = replication.providerA().objectsChangedSinceLastReplication();
    ObjectSet<Object> changesOnClient = replication.providerB().objectsChangedSinceLastReplication();
    System.out.println("Changes on Server: " + changesOnHost.size());
    System.out.println("Changes on Client: " + changesOnClient.size());
    // then iterate over both change-sets and replicate it
    for (Object changedObjectOnClient : changesOnClient)
    {
        replication.replicate(changedObjectOnClient);
    }
    for (Object changedObjectOnHost : changesOnHost)
    {
        replication.replicate(changedObjectOnHost);
    }
    replication.commit();
}

public void writeToClient(Object object)
{
    clientContainer.store(object);
    clientContainer.commit();
}

Works just fine for new objects created and written to a database.

If I write a changed object from one of these databases, such as a field change, the sync method when run will pick up that there is a changed object and it is in fact the correct one and its field has been changed. However, I am not seeing that object being replicated in the other database. Its field is not the same as the changed object's field.

Do I simply have a misconception about db4o's replication abilities? This is a bit out of my league as a 2nd year but if anyone can see where I am going wrong I would greatly appreciate it.

Was it helpful?

Solution

I managed to get the version 8 to replicate correctly. I was not following the tutorial exactly and made assumptions (Although without clarification it is still an assumption).

It seems that instantiating the ReplicationSession and the ReplicationProviders at the time of syncing is critical. I changed my code so that at SyncDatabases() these are created and not kept (And I guess garbage collection takes care of them).

public void syncDatabases()
{        
    // First get the changes of the two replication-partners
    Db4oEmbeddedReplicationProvider providerA = new Db4oEmbeddedReplicationProvider(hostContainer);
    Db4oEmbeddedReplicationProvider providerB = new Db4oEmbeddedReplicationProvider(clientContainer);
    ReplicationSession replication = Replication.begin(providerA, providerB);

    ObjectSet<Object> changesOnHost = replication.providerA().objectsChangedSinceLastReplication();
    ObjectSet<Object> changesOnClient = replication.providerB().objectsChangedSinceLastReplication();

    // then iterate over both change-sets and replicate it
    for (Object changedObjectOnClient : changesOnClient)
    {
        replication.replicate(changedObjectOnClient);
    }
    for (Object changedObjectOnHost : changesOnHost)
    {
        replication.replicate(changedObjectOnHost);
    }
    replication.commit();

    replication.replicateDeletions(Object.class);
}

The constructor just runs openDb() to get the objectContainers initialised.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top