Sync
Channels/Data Routing
In the Access Control lesson we discussed how the Couchbase Sync Gateway supports Authorization and Access Control functions. In this lesson we discuss how it can be used for Data Synchronization and Routing.
A Sync Gateway configuration file determines the runtime behavior of Sync Gateway, including server configuration and the database or set of databases with which a Sync Gateway instance can interact.
Sync Gateway uses channels to make it easy to share a database between a large number of users and control access to the database. Conceptually, a channel could be viewed as a tag. Every document in the database belongs to a set of channels, and a user is granted appropriate access a set of channels. A channel is used to:
-
Partition the data set.
-
Authorize users to access documents.
-
Minimize the amount of data synced down to devices.
In the Sync Gateway installation section, we walked you through the steps to launch Sync Gateway with a specific config file.
Open the sync-gateway-config-travelsample.json file located at
https://github.com/couchbaselabs/mobile-travel-sample/blob/master/sync-gateway-config-travelsample.json.
It includes the sync function which is a JavaScript function whose source code is stored in the Sync Gateway’s database configuration file.
/* Routing */
// Add doc to the user's channel.
channel("channel." + username);
Shared Bucket Access
Before you begin this lesson, confirm that you have Sync Gateway up and running by following the instructions in the Sync Gateway installation section.
Sync Gateway and Couchbase Server mobile and server/web applications can read and write to the same bucket [1]. It is an opt-in feature that can be enabled in the Sync Gateway configuration file.
The sync metadata used by the Sync Gateway for replication with mobile clients is stored in the Extended Attributes or XAttrs associated with the document.
The capability can be enabled through a configuration setting in the sync gateway config file.
Note that if you are using Enterprise Edition of Sync Gateway [2], then the "import_docs" flag is optional. Every node with "enable_shared_bucket_access" set to "true" will automatically import document mutations from the server bucket.
Open the sync-gateway-config-travelsample.json file located at https://github.com/couchbaselabs/mobile-travel-sample/blob/master/sync-gateway-config-travelsample.json
"import_docs": "true",
"enable_shared_bucket_access": true
You can specify the Couchbase Server documents that need to be imported and processed by the Sync Gateway by defining an import filter function. In our demo, we will only be synchronizing the "user" document. So every other document type is ignored.
function(doc) {
/* Just ignore all the static travel-sample files */
if (doc._deleted == true ) {
return true;
}
if (doc.type == "landmark" || doc.type == "hotel" || doc.type == "airport" || doc.type =="airline" || doc.type == "route") {
return false;
}
return true;
}
Replication
Replication is the process by which clients running Couchbase Lite synchronize database changes with the remote (server) database.
-
Pull Replication is the process by which clients running Couchbase Lite download database changes from the remote (server) source database to the local target database.
-
Push Replication is the process by which clients running Couchbase Lite upload database changes from the local source database to the remote (server) target database.
Couchbase Mobile [3] replication protocol is implemented as a messaging protocol layered over WebSocket.
The replication process can be continuous or one shot.
-
In “Continuous” replication mode, the changes are continually synchronized between the client and Sync Gateway in real time.
-
In “One shot” mode, the changes are synchronized once and the connection between the client and server disconnects. When any future changes need to be pushed up or pulled down, the client must start a new replication.
Open the file app/src/android/java/…/util/DatabaseManager.java.
We will review the method startPushAndPullReplicationForCurrentUser(String username, String password).
public static void startPushAndPullReplicationForCurrentUser(String username, String password) {
...
}
First, you initialize the URL object which points to the Sync Gateway instance to synchronize with.
public static String mSyncGatewayEndpoint = "ws://10.0.2.2:4984/travel-sample";
URI url = null;
try {
url = new URI(mSyncGatewayEndpoint);
} catch (URISyntaxException e) {
e.printStackTrace();
}
Next, you will configure the replication.
The ReplicatorConfiguration is initialized with the local database and URL of the target DB on Sync Gateway.
The replicatorType in the Replicator Config specifies the type of replication.
In the code snippet in the Travel App, it is pushAndPull indicating that both push and pull replication is enabled.
The continuous mode is set to true in the Travel app.
ReplicatorConfiguration config = new ReplicatorConfiguration(database, new URLEndpoint(url));
config.setReplicatorType(ReplicatorConfiguration.ReplicatorType.PUSH_AND_PULL);
config.setContinuous(true);
The Replicator is configured with relevant authentication credentials. The list of users that are granted access sync with the Sync Gateway are created as discussed in the Access Control section
config.setAuthenticator(new BasicAuthenticator(username, password));
The Replicator is initialized with the specified configuration
Replicator replicator = new Replicator(config);
A change listener callback block is registered to listen for replication changes. Every time, there is a push or pull change, the callback is invoked.
replicator.addChangeListener(new ReplicatorChangeListener() {
@Override
public void changed(ReplicatorChange change) {
if (change.getReplicator().getStatus().getActivityLevel().equals(Replicator.ActivityLevel.IDLE)) {
Log.e("Replication Comp Log", "Schedular Completed");
}
if (change.getReplicator().getStatus().getActivityLevel().equals(Replicator.ActivityLevel.STOPPED) || change.getReplicator().getStatus().getActivityLevel().equals(Replicator.ActivityLevel.OFFLINE)) {
// stopReplication();
Log.e("Rep schedular Log", "ReplicationTag Stopped");
}
}
});
Replication is started
replicator.start();