Managing clusters using the Java SDK with Couchbase Server
The primary means for managing clusters is through the Couchbase Web UI which provides an easy to use interface for adding, removing, monitoring and modifying buckets. In some instances you may wish to have a programmatic interface. For example, if you wish to manage a cluster from a setup script, or if you are setting up buckets in test scaffolding.
The Java SDK also comes with some convenience functionality for common Couchbase management requests.
Management operations in the Java SDK may be performed through several interfaces depending on the object:
-
ClusterManager
class (obtained viaCluster#clusterManager(string, string)
with the administrative username and password). -
BucketManager
class (obtained viaBucket#bucketManager()
).
Getting Information About the Cluster
When you call ClusterManager#info()
it returns a ClusterInfo
object that contains both raw and typed information on the overall cluster state.
In addition to the ClusterInfo#raw()
method that provides direct access to everything returned by the server, the following methods are available:
-
To find out the minimum version of all nodes in the cluster, you can use the
ClusterInfo#getMinVersion()
method. For example, if you have 3 nodes running version 3.1 and one running version 3.0.3, it reports version 3.0.3. -
If you want to check if a certain feature is enabled on the cluster, you can use the
checkAvailable
method and pass in one of theCouchbaseFeature
enumerations. It uses the minimum cluster version as a basis and then asserts it against the minimum version of the passed in feature. The SDK uses this internally to determine if specific integration tests can be executed against the connected cluster, and so can you. -
The
getAllVersions
method returns the version number of all nodes in the cluster.
Creating and Removing Buckets
The ClusterManager
class may be used to create and delete buckets from the Couchbase cluster.
It is instantiated through the Cluster
's clusterManager
method, providing the administrative username and password.
Cluster cluster = CouchbaseCluster.create("127.0.0.1"); ClusterManager clusterManager = cluster.clusterManager("Administrator", "123456");
To create a bucket, use the ClusterManager#insertBucket(BucketSettings)
method.
The BucketSettings
can be created via a builder, DefaultBucketSettings.builder()
.
This class is also used to expose information about an existing bucket (ClusterManager#getBucket(string)
) or to update an existing bucket (ClusterManager#updateBucket(BucketSettings)
).
Note that any property that is not explicitly set when building the BucketSettings will use the default value.
In the case of the update, this is not necessarily the currently configured value, so you should be careful to set all properties to their correct expected values when updating an existing bucket configuration.
|
Only name
and type
parameters are mandatory for the BucketSettings
.
Here is the list of parameters available:
-
name
: The name of the bucket (mandatory to create one, cannot be updated). -
type
: The type of the bucket (mandatory to create one, cannot be changed). Defaults toBucketType.COUCHBASE
, but can also beBucketType.MEMCACHED
to create a cache bucket. -
quota
: How much memory should each node use for the bucket. This number is specified in megabytes. -
password
: If specified, makes this bucket password protected, forcing future connects (using theBucket
) class to specify thepassword
parameter. -
enableFlush
: Enables theBucketManager#flush()
operation to be performed on this bucket (see the Flushing Buckets section below). -
replicas
: The number of replicas to use for the bucket. -
indexReplicas
: Wether or not to replicate indexes. -
port
: The optional proxy port.
The following example updates an existing "hello" bucket (notice how all parameters are set):
BucketSettings bucketSettings = new DefaultBucketSettings.Builder() .type(BucketType.COUCHBASE) .name("hello") .password("") .quota(120) // megabytes .replicas(1) .indexReplicas(true) .enableFlush(true) .build(); manager.updateBucket(bucketSettings);
Once you no longer need to use the bucket, you may delete the bucket using the ClusterManager#removeBucket(string)
method:
clusterManager.removeBucket("new_bucket");
Flushing Buckets
When a bucket is flushed, all content is removed. Because this operation is potentially dangerous it is disabled by default for each bucket. Bucket flushing may be useful in test environments where it becomes a simpler alternative to removing and creating a test bucket. You may enable bucket flushing on a per-bucket basis using the Couchbase Web Console or when creating a bucket.
You may flush a bucket in the Java SDK by using the BucketManager#flush()
method:
bucket.bucketManager().flush()
The flush
operation may fail if the bucket does not have flush enabled:
com.couchbase.client.java.error.FlushDisabledException: Flush is disabled for this bucket. at com.couchbase.client.java.bucket.BucketFlusher$6.call(BucketFlusher.java:145) at com.couchbase.client.java.bucket.BucketFlusher$6.call(BucketFlusher.java:140) ...
N1QL Index Management
You can create and drop N1QL indexes using the SDK. This is especially useful when setting up new applications, or simply when ensuring that a given bucket has certain indexes defined. Indexes can be defined using actual N1QL statements or by using convenience functions within the SDK.
You can manage indexes in the Java SDK using the BucketManager
class, with its various N1QL related methods: listN1qlIndexes()
, createN1qlIndex(...)
, etc...
The following example creates a N1QL secondary index named "fooBar" on the "test" bucket, indexing fields "foo" and "bar":
//shortcut for the purpose of this snippet only BucketManager testManager = CouchbaseCluster.open("127.0.0.1").openBucket("test").bucketManager(); boolean ignoreIfExists = true; // if index exists, don't throw exception boolean defer = false; // create the index immediately testManager.createN1qlIndex("fooBar", ignoreIfExists, defer, "foo", "bar");
View Management
Views are stored in design documents. The SDK provides convenient methods to create, retrieve, and remove design documents. To set up views, you create design documents that contain one or more view definitions, and then insert the design documents into a bucket. Each view in a design document is represented by a name and a set of MapReduce functions. The mandatory map function describes how to select and transform the data from the bucket, and the optional reduce function describes how to aggregate the results.
In the Java SDK, design documents are represented by the DesignDocument
class and View
interface.
All operations on design documents are performed on a BucketManager
instance.
Use the DefaultView.create()
factory method to create a View
.
To inspect design documents, you can either retrieve them by name (bucketManager.getDesignDocument("landmarks")
) or iterate through a list of documents (bucketManager.getDesignDocuments();
).
To create or update design documents, use the insertDesignDocument(DesignDocument)
and upsertDesignDocument(DesignDocument)
methods.
You can also publish a design document that is in development mode (that is, running only on a small fraction of the documents) to production mode by using the publishDesignDocument(string)
method.
When you initialize the design document, you can also specify how often to trigger indexing on documents and replicas. The following table lists the available options:
Option | Description |
---|---|
|
The minimum changes to perform on a design document before indexing is triggered. |
|
The minimum changes to perform on a design document before replica indexing is triggered. |
The following example inserts a design document with two regular views and one spatial view into a bucket named travel-sample
:
//shortcut for the purpose of this snippet only BucketManager bucketManager = CouchbaseCluster.open("127.0.0.1").openBucket("travel-sample").bucketManager(); // Initialize design document DesignDocument designDoc = DesignDocument.create( "landmarks", Arrays.asList( DefaultView.create("by_country", "function (doc, meta) { if (doc.type == 'landmark') { emit([doc.country, doc.city], null); } }"), DefaultView.create("by_activity", "function (doc, meta) { if (doc.type == 'landmark') { emit(doc.activity, null); } }", "_count"), SpatialView.create("by_coordinates", "function (doc, meta) { if (doc.type == 'landmark') { emit([doc.geo.lon, doc.geo.lat], null); } }") ) ); // Insert design document into the bucket bucketManager.insertDesignDocument(designDoc);
When you want to update an existing document with a new view (or a modification of a view’s definition), you can use the However, this method needs the list of views in the document to be exhaustive, meaning that if you just create the new view definition as previously and add it to a new The solution is to perform a |
//(note: obtaining the bucketManager is omitted in this snippet) // Get design document to be updated DesignDocument designDoc = bucketManager.getDesignDocument("landmarks"); // Update the "by_country" view, adding a reduce designDoc.views().add( DefaultView.create("by_country", //reuse same name "function (doc, meta) { if (doc.type == 'landmark') { emit([doc.country, doc.city], null); } }", //same map function "_count" //added reduce function ) ); // Resend to server bucketManager.upsertDesignDocument(designDoc);
To remove a design document from a bucket, pass its name to the removeDesignDocument
method.