Membase Sdk Java Tutorial 1.7

16
8/13/2019 Membase Sdk Java Tutorial 1.7 http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 1/16 1 Membase and Java Tutorial Copyright © 2010-2013 Couchbase, Inc. Contact [email protected] . For documentation license information, see Section 13.1, “Documentation License” . For all license information, see Section 13, “Licenses” . Abstract Note. The following document is still in production, and is not considered complete or exhaustive. Last document update : 07 Mar 2013 00:06; Document built : 06 Sep 2013 02:10. Documentation Availability and Formats. This documentation is available online: HTML Online . For other documentation from Couchbase, see Couchbase Documentation Library Contact: [email protected] or couchbase.com Tabl e of Contents 1. Prereq uisites ....................... .................................................................................................................... 1 2. Install ation .................................. ........................................................................................................... 2 3. Buildi ng a Chat Room Application ........... ................................................................................................. 2 4. Conne cting with the Server ...................................................................................................................... 2 5. Confi guring Logging ............................................................................................................................... 4 6. Shutting Down a Client Connection ........................................................................................................... 5 7. Increment and Decrement Operations ......................................................................................................... 5 8. Prepend and Append Operations ................................................................................................................ 6 9. Using Buckets ...................................................................................................................................... 10 10. Error Handling .................................................................................................................................... 12 11. Using vbuckets ................................................................................................................................... 13 12. The TAP API ..................................................................................................................................... 14 13. Licenses ............................................................................................................................................. 15 13.1. Documentation License .............................................................................................................. 15 1. Prerequisites In order to follow along in this tutorial you need the following items to be installed a nd functional. Maven is only required if you want to take the attached tutorial starter project and follow the steps. You may also build this code in the IDE of your choice, but with Maven you can use command line and a text editor and get up and running quickly. Java SE 6 installed Maven 3 installed Me mbase server installed and running

Transcript of Membase Sdk Java Tutorial 1.7

Page 1: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 1/16

1

Membase and Java Tutorial

Copyright © 2010-2013 Couchbase, Inc. Contact [email protected] .

For documentation license information, see Section 13.1, “Documentation License” . For all license information, seeSection 13, “Licenses” .

Abstract

Note. The following document is still in production, and is not considered complete or exhaustive.

Last document update : 07 Mar 2013 00:06; Document built : 06 Sep 2013 02:10.

Documentation Availability and Formats. This documentation is available online: HTML Online . For other documentation fromCouchbase, see Couchbase Documentation Library

Contact: [email protected] or couchbase.com

Tabl e of Contents1. Prereq uisites ....................... .................................................................................................................... 12. Install ation .................................. ........................................................................................................... 23. Buildi ng a Chat Room Application ........... ............................................... .................................................. 24. Conne cting with the Server .................................................. ....................................................... ............. 2

5. Confi guring Logging ....................................................... ....................................................... ................. 46. Shutting Down a Client Connection ..... ..... ...... ..... ...... ..... ...... ...... ..... ...... ..... ...... ...... ..... ...... ..... ...... ...... ..... .. 57. Increment and Decrement Operations ...... ..... ...... ...... ..... ...... ..... ..... ...... ..... ...... ..... ...... ...... ..... ...... ..... ...... ..... 58. Prepend and Append Operations ................................................................................................................ 69. Using Buckets ................................................................ ........................................................ .............. 1010. Error Handling ........... ........................................................ ........................................................ ......... 1211. Using vbuckets ......... ........................................................ ........................................................ .......... 1312. The TAP API ................................................. ........................................................ ............................ 1413. Licenses .................................... ........................................................ ................................................. 15

13.1. Documentation License ..... ...... ...... ..... ...... ..... ...... ...... ..... ...... ..... ...... ...... ..... ...... ..... ...... ...... ..... .... 15

1. Prerequisites

In order to follow along in this tutorial you need the following items to be installed a nd functional. Maven is only requiredif you want to take the attached tutorial starter project and follow the steps. You may also build this code in the IDE of your choice, but with Maven you can use command line and a text editor and get up and running quickly.

• Java SE 6 installed

• Maven 3 installed

• Me mbase server installed and running

Page 2: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 2/16

Membase and Java Tutorial

2

2. InstallationIf you are using Maven, download the spymemcached JAR file file and install it into your Maven repository. If you wantto use another IDE, download the library and put it into your classpath or build path.

We will use Maven in this tutorial, but it is in no way a requirement for using the library or interfacing with Membase.

It is simply a convenience for keeping this tutorial as easy to follow as possible. The following is a recent version of spymemcached that includes some very new APIs that will be discussed later in this tutorial.

a. Download spymemcached-2.6.jar

b. Execute the Maven command to save the jar file into your local maven repository:

$ mvn install:install-file -Dfile=memcached-2.6.jar \ -DgroupId=spy -DartifactId=spymemcached \ -Dversion=2.6 \ -Dpackaging=jar

3. Building a Chat Room Application

For the example in this tutorial we will be writing a distributed chat room application, where a nearly unlimited numberof people could potentially be talking at the same time. The previous statements made by other users in the chat room willbe remembered in memory for a certain period of time, after which they will be forgotten. When a user first connects tothe server, they will be sent the entire transcript of messages that have not timed out on the server, after which they will beable to participate anonymously in the ongoing conversation. At any point in the conversation, they may quit, by typingthe word 'quit'. Implementing these requirements will demonstrate a number of important API methods of the spymem-cached client library talking to a Membase server, which is providing the distributed storage capabilities.

Let's get started.

Download tutorial-start.zip and extract it into a directory. Open a command shell, navigate to that directory, and type thefollowing commands

$ mvn assembly:assembly

$ java -jar target\membasetutorial-exe.jarHello, world!

When you see the words 'Hello, world!' you are ready to continue on with the tutorial.

4. Connecting with the ServerThe client library contains a number of different ways to connect to a Membase server. First, let's discuss these methodsand then we will use one of those methods to make the chat room client application connect with the Membase installa-tion.

There are three main ways of connecting with one or more Membase servers from the client library:

a. A direct, ASCII protocol connection can be made by creating an instance of the MemcachedClient object and passingin one or more InetSocketAddress instances. For example:

MemcachedClient c = new MemcachedClient(new InetSocketAddress("hostname", portNum));

or:

MemcachedClient c = new MemcachedClient(AddrUtil.getAddresses("server1:11211 server2:11211"));

b. Use one of the connection factory constructors to establish a binary protocol connection with your server:

Page 3: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 3/16

Membase and Java Tutorial

3

MemcachedClient c = new MemcachedClient( new BinaryConnectionFactory(), AddrUtil.getAddresses("server1:11211 server2:11211"));

c. Create a connection that is authenticated using SASL by using a ConnectionFactoryBuilder . The binary proto-col must be used with a SASL authenticated connection. In the case of Membase, the username and password you usehere are based on the buckets you have defined on the server. The username is the bucket name, and the password is the

password used when creating the bucket. We will cover this more later, but in the meantime here is the code you willneed to authenticate and start a binary protocol session:

AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, new PlainCallbackHandler(username, password));

MemcachedClient c = new MemcachedClient( new ConnectionFactoryBuilder().setProtocol(Protocol.BINARY) .setAuthDescriptor(ad) .build(), AddrUtil.getAddresses(host));

Let's start making modifications to the tutorial Main.java class in order to make our first connection. Here we will be mak-ing an unauthenticated ASCII protocol connection to the server. After you have the tutorial code working, you can easilygo back and change the connect() method to use the binary protocol instead, or even change it to make an authenticat-ed SASL connection.

First, modify main to read:

public static void main(String[] args) {

if (args.length != 1) { System.err.println("usage: serveraddress"); System.exit(1); }

try {

new Main().run(args[0]);

} catch (Exception ex) { System.err.println(ex); client.shutdown(); }

}

Notice that an instance of the class is created and its run() method is called to get things started, passing the first argu-ment on the command line to it. This is just so that we don't have to make everything static. It also sets up a default excep-tion handler for everything so that the methods will be much simpler.

Add the run() method, implemented as follows:

public void run(String serverAddress) throws Exception {

System.out.println(String .format("Connecting to %s", serverAddress));

connect(serverAddress);

client.shutdown(1, TimeUnit.MINUTES);

}

Next, add the connect() method:

private void connect(String serverAddress)throws Exception {

InetSocketAddress address =new InetSocketAddress(serverAddress, 11211); client = new MemcachedClient(address);

Page 4: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 4/16

Membase and Java Tutorial

4

}

You'll recognize this constructor as a single server connection. What if you want to know more about the current connec-tion state such as when the connection has been gained, or lost? You can add a connection observer by modifying the con-nect method and adding the following lines:

client.addObserver(new ConnectionObserver() {

public void connectionLost(SocketAddress sa) { System.out.println("Connection lost to "+sa.toString()); }

public void connectionEstablished(SocketAddress sa, int reconnectCount) { System.out.println("Connection established with " + sa.toString()); System.out.println("Reconnect count: " + reconnectCount); } });

You've only connected with one server, but what if it goes offline? This can easily be fixed by changing the first threelines of the connect method:

List<InetSocketAddress> addresses = AddrUtil.getAddresses(serverAddress); client = new MemcachedClient(addresses);

The AddrUtil.getAddresses() method takes a string and parses multiple space delimited server colon port stringssuch as:

"server1:11211 server2:11211 10.0.0.1:11211 2001:0DB8:AC10:FE01:::11211"

This class will even work with colon-delimited IPv6 addresses.

Finally, you need to create the static member variable to store the client instance at the top of the class:

private static MemcachedClient client;

Now you can try compiling and running the application:

$ mvn assembly:assembly

$ java -jar target\membasetutorial-exe.jar "10.0.0.33:11211 10.0.0.57:11211"

Connecting to 10.0.0.33:11211 10.0.0.57:1121115-May-2011 5:02:33 PM net.spy.memcached.MemcachedConnection <init>INFO: Added {QA sa=/10.0.0.33:11211, #Rops=0, #Wops=0, #iq=0, topRop=null,topWop=null, toWrite=0, interested=0} to connect queue15-May-2011 5:02:33 PM net.spy.memcached.MemcachedConnection <init>INFO: Added {QA sa=/10.0.0.57:11211, #Rops=0, #Wops=0, #iq=0, topRop=null,topWop=null, toWrite=0, interested=0} to connect queue15-May-2011 5:02:33 PM net.spy.memcached.MemcachedConnection handleIOINFO: Connection state changed for sun.nio.ch.SelectionKeyImpl@1621e42Connection established with /10.0.0.33:11211Reconnected count: 115-May-2011 5:02:33 PM net.spy.memcached.MemcachedConnection handleIOINFO: Connection state changed for sun.nio.ch.SelectionKeyImpl@b09e89Connection established with /10.0.0.57:11211Reconnected count: 1

You can see that the client library outputs some logging statements indicating that it is making two connections. You canalso see that the connection observer you added to the connect() method is being called with the addresses of the twoservers as they are connected and the reconnection count is 1 indicating that the network is in good shape. It's ready to getsome work done.

5. Configuring LoggingIf you want to configure the logging framework used at runtime you can add the following to the run() method:

Page 5: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 5/16

Membase and Java Tutorial

5

System.setProperty("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.SunLogger");

Or:

System.setProperty("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.Log4JLogger");

The default logger simply logs everything to the standard error stream.

6. Shutting Down a Client ConnectionThe client application will remain running until the client.shutdown() or client.shutdown(long, TimeU-nit) methods are called.

The shutdown() method shuts the application down immediately and any outstanding work will be stopped.

The shutdown(long, TimeUnit) method will actually wait until any outstanding queued work is completed beforeshutting down, but it will time out in the given period of time. This would be the preferred method of shutting down theclient connection.

7. Increment and Decrement OperationsThe API contains methods that are able to atomically increment a variable in the database and decrement a variable. Effec-tively this means that these operations are safe for use by any client across the cluster at any time and there is some guar-antee that these will be done in the right order. We will demonstrate these methods by tracking the total number of chatclients connected to the server.

Add the following lines to the run() method after the connect method:

connect(serverAddress);

register(); unregister();

client.shutdown(1, TimeUnit.MINUTES);

Then add the following two methods to the end of the class:

private boolean register() throws Exception {

userId = client.incr("UserId", 1, 1); System.out.println("You are user "+userId+".");

userCount = client.incr("UserCount", 1, 1); System.out.println("There are currently "+userCount+" connected.");

return true; }

private void unregister() throws Exception {

client.decr("UserCount", 1); System.out.println("Unregistered.");

}

These two methods demonstrate the use of the incr and decr methods, which increment and decrement a variable, re-spectively. The application you are building uses this to keep track of how many users are currently running the program.This particular overload of the incr method takes a default value that it will use if the key UserCount does not exist, andwill return the current count. In this case the first user will be assigned user number 1. Finally, when the unregister methodis called, the decr method will be called to subtract 1 from the UserCount value.

Finally, you must add the following member variables to the top of the class:

Page 6: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 6/16

Membase and Java Tutorial

6

private long userId = 0; private long userCount = 0;

If you compile and run this program now, you will see the following output:

$ mvn assembly:assembly$ java -jar target\membasetutorial-exe.jar

...You are user 1.There are currently 0 connected.Unregistered.15-May-2011 9:07:39 PM net.spy.memcached.MemcachedClient runINFO: Shut down memcached client

Up to this point, the application is doing some very simple things, allowing a user to connect, and keeping track of howmany users and currently connected. It's time to start adding some data to the database, and providing some methods to in-teract between multiple clients.

8. Prepend and Append OperationsWe have implemented a client application that tracks how many clients are connected at the moment. Let's add the func-

tionality to track the actual users that are currently connected, by storing a user name token for each connected user.We'll nominate a key to keep a list of all of the user numbers that are currently connected, and then when a user discon-nects, remove their entry from the key. Right away, though, this presents a challenge. How can we guarantee that twousers starting at exactly the same time don't mess up the value by overwriting each other's edits? Let's find out.

The API contains a method called append . It takes a special value called a CAS, which stands for Compare And Swap,but where do we get this number? There is another method called gets, which returns an object that can be asked for theCAS value we need to perform an append operation. Another interesting thing about the append method is that it returns aFuture<Boolean> , which means it is an asynchronous method. You can use the value it returns to wait for an answerindicating whether the operation succeeded or failed. Asynchronous methods also allow the code to do other things with-out having to wait for the result. At a later point in the code, the result of the operation can be obtained by using the futurevariable.

You will be using the append method in this tutorial, but the prepend method functions in exactly the same way exceptthat append adds a string to the end of a value in the database, while prepend puts a string at the front of a value.

Both the append and prepend methods operate atomically, meaning they will perform the operation on a value in thedatabase and finish each operation before moving on to the next. You will not get interleaved appends and prepends. Of course, the absolute order of these operations is not guaranteed.

The lines that are in bold-face should be changed in the register method of the code:

private String getUserNameToken() { return String.format("<User-%d>", userId); }

private boolean register() throws Exception {

userId = client.incr("UserId", 1, 1); System.out.println("You are user " + userId + ".");

CASValue<Object> casValue = client.gets("CurrentUsers");

if (casValue == null) {

System.out.println("First user ever!");

client.set("CurrentUsers", Integer.MAX_VALUE, getUserNameToken()).get();

} else {

Page 7: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 7/16

Membase and Java Tutorial

7

Future<Boolean> appendDone = client.append(casValue.getCas(), "CurrentUsers", getUserNameToken());

if (appendDone.get()) { System.out.println("Registration succeeded."); } else { System.out.println("Sorry registration failed."); return false;

}

}

userCount = client.incr("UserCount", 1, 1); System.out.println("There are currently " + userCount + " connected.");

return true; }

First you can see that the client.gets("CurrentUsers") method is called to get a casValue . If that value isnull, it means that no one has ever connected, so that user is the first user. So we will simply set the value of Curren-tUsers using the new getUserNameToken() method.

Otherwise, we will append our userid to the list of users. To do this, we need to call the append method with the CAS

that is in the casValue by calling its getCas() method. The append method is also asynchronous and returns aFuture<Boolean> . Calling the get() method on that future will return its value when its operation has been per-formed. The append operation can possibly fail, if for instance the size of the list of usernames exceeds the maximum sizeof a value in the membase bucket. So we handle both cases. If it returns true, we tell the user that the registration was asuccess. Otherwise the registration failed, so we'll tell the user this and return false to tell the main program that somethingwent wrong.

You need to modify the run() method as well, to handle the possibility of the register method returning false:

connect(serverAddress);

if (register()) { unregister(); }

client.shutdown(1, TimeUnit.MINUTES);

Now, we need to clean up the user list when a user leaves. We will be modifying the unregister method to be very carefulto remove the current userId from the CurrentUsers list before finishing. The Java client library has a very elegant API thatprovides a way to ensure that the operation is retried if another client has beat us to making their change to the same data-base value. This API uses a CASMutation<T> and CASMutator<T> to perform the modification safely. These class-es require a Transcoder<T> so that everything can be nice and type safe. Add the following code just before the un-register() method:

class StringTranscoder implements Transcoder<String> {

final SerializingTranscoder delegate = new SerializingTranscoder();

public boolean asyncDecode(CachedData d) { return delegate.asyncDecode(d); }

public String decode(CachedData d) { return (String)delegate.decode(d); }

public CachedData encode(String o) { return delegate.encode(o); }

public int getMaxSize() { return delegate.getMaxSize(); }

Page 8: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 8/16

Membase and Java Tutorial

8

}

Then, add the following bold lines to the unregister() method:

private void unregister() throws Exception {

CASMutation<String> mutation = new CASMutation<String>() { public String getNewValue(String current) {

return current.replaceAll(getUserNameToken(), ""); } };

Transcoder<String> transcoder = new StringTranscoder(); CASMutator<String> mutator = new CASMutator<String>(client, transcoder); mutator.cas("CurrentUsers", "", 0, mutation);

client.decr("UserCount", 1); System.out.println("Unregistered.");

}

The mutation anonymous class instance defines what to change the string to, once it is obtained from the database. Themutator instance starts the cas() method that that uses the mutation. What happens is that the operation will be retrieduntil it succeeds. If two clients are writing to the same database value at the same time, one of the clients will need to retrybecause its CAS value will not match the database after the operation. We will discuss the CAS error handling more lateron. All you need to know at the moment is that the mutator will eventually succeed in storing its value to the database, andthat value will be consistent with what was written by other clients, which is very convenient.

It is now time to complete the functionality of the tutorial application by writing a thread that will output the messages thatusers type as well as a method of getting input from the users.

First add the following member variable to the class:

private Thread messageThread;

Next, modify the run() method again to add the following lines in bold:

if (register()) { startMessageThread();

processInput(); unregister(); messageThread.interrupt(); }

Now we will need to write a few helper methods, the first is:

private void printMessages(long startId, long endId) {

for (long i = startId; i <= endId; i++) { String message = (String)client.get("Message:" + i); if (message != null) System.out.println(message); }

}

This method just iterates through a set of message numbers and prints the message to the screen. Membase does not allowiteration of keys, but that's okay, we know exactly what pattern the key names follow, so we can do this.

The second method helps to find the oldest message that hasn't expired in the database, starting at the last message andrunning back toward the first message. Eventually it will find the first message and will return its number, considering thatit will have run one past the end, it needs to do a little fix-up to return the correct number:

private long findFirstMessage(long currentId) { CASValue<Object> cas = null; long firstId = currentId; do {

Page 9: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 9/16

Membase and Java Tutorial

9

firstId -= 1; cas = client.gets("Message:" + firstId); } while (cas != null);

return firstId + 1; }

Finally we come to the method that prints out all of the messages as they come in. It's somewhat complicated so we'll de-

scribe it in detail afterward.private void startMessageThread() {

messageThread = new Thread(new Runnable() { public void run() {

long messageId = -1;

try { while (!Thread.interrupted()) {

CASValue<Object> msgCountCas = client.gets("Messages");

if (msgCountCas == null) { Thread.sleep(250); continue; }

long current = Long.parseLong((String)msgCountCas.getValue());

if (messageId == -1) { printMessages(findFirstMessage(current), current); } else if (current > messageId) { printMessages(messageId + 1, current); } else { Thread.sleep(250); continue; }

messageId = current;

}

} catch (InterruptedException ex) {

} catch (RuntimeException ex) { }

System.out.println("Stopped message thread."); } });

messageThread.start();

}

This code creates a new thread of execution and assigns it to the messageThread variable. It creates an anonymousRunnable class that implements a run() method inline.

The messageId variable is set to a sentinel value so that we know when it is the first time through the while loop. Thewhile loop will iterate until the thread has been interrupted.

First, in the while loop, we write client.gets("Messages"), which will return null if the value does not exist (in which casethe loop sleeps for a little while and continues back to the top). Or the method will return a CASValue<Object> in-stance that we can use to obtain the current message id.

If this is the first time through the loop (messageId == -1) , we need to print out all of the messages from the first tothe current message.

Otherwise if the current messageId is bigger than what we've previously seen, it means that some new messages havecome in since we last checked, so we will print them out.

Page 10: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 10/16

Membase and Java Tutorial

10

Finally, nothing has changed since we last checked so just sleep some more.

At the end of the loop, we just make sure that the current message id is remembered for the next iteration of the loop. Ex-ceptions are handled by suppressing them, and if the while loop exits we'll print a message saying the message threadstopped.

At the end of the method, the thread is actually started.

Great, so, now if messages come in, we'll display them. Also, when we first start the application, all of the messagesstored in the database will be displayed. We need to implement the actual method that allows the user to interact with thedatabase:

private static void processInput() { boolean quit = false;

System.out.println("Enter text, or /who to see user list, or /quit to exit.");

do { String input = System.console().readLine(); if (input.startsWith("/quit")) { quit = true; } else if (input.startsWith("/who")) { System.out.println("Users connected: "

+ client.get("CurrentUsers")); } else { // Send a new message to the chat long messageId = client.incr("Messages", 1, 1); client.set("Message:" + messageId, 3600, getUserNameToken() + ": " + input); }

} while (!quit);

}

The method keeps track of a quit variable to know when to exit the do/while loop, then prints out some simple instructionsfor the user.

The console is read one line at a time, and each is checked to see if it starts with a command. If the user has typed '/quit'

the quit flag will be set, and the loop will exit.

If the user has typed '/who' the value of the CurrentUsers variable will be output to the screen, so that at any time auser can check who is currently online.

Otherwise, the line is treated as a message. Here we increment the Messages key and use that value as a message id. Thenthe client.set() method is called with a key of Message:MessageId with a timeout of one hour, followed by theuser's name and the text that they entered.

These changes to the database will be noticed by the message thread, and output to the screen. Of course this means thateach user will see his or her messages repeated back to them.

If you compile and run the program in multiple terminal windows, you can talk to yourself. This is about as fun as things

can get, isn't it? Notice how intelligent you can be.

9. Using BucketsUp to this point, the test application has been using the default bucket. This is because it is not using the binary protocol,and it is not authenticated. The default bucket on Membase can be useful when you first start out, but as you build morecomplex applications, you may want to partition your data into different buckets (see Figure 1) to improve fault toleranceby boosting replication or just so that one bucket can be cleared without affecting all of the data you have stored in otherbuckets. You may also want to partition your key space among several applications to avoid naming collisions.

Page 11: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 11/16

Membase and Java Tutorial

11

Figure 1. Figure 1: Creating a private bucket.

Figure 1, shows the dialog in the Membase Web Console that demonstrates creating a new bucket called private with

two replicas. Here you also choose a password to protect the bucket during SASL authentication. How do you access thisbucket? You have already learned about how to make a binary SASL authenticated connection to Membase. If you use thebucket name as the username, and the password you provided when creating the bucket, you will connect to the privatebucket for data storage. The following code would accomplish this:

// We have used private as the username and private as the password// but you would not do this, you would be much smarter and use// something much harder to guess.AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, new PlainCallbackHandler("private", "private"));

MemcachedClient c = new MemcachedClient(

Page 12: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 12/16

Membase and Java Tutorial

12

new ConnectionFactoryBuilder().setProtocol(Protocol.BINARY) .setAuthDescriptor(ad) .build(), AddrUtil.getAddresses(host));

10. Error Handling

At this point, you may still be wondering how CAS values are used to prevent clients from writing over values that werechanged by another client. Here is the answer:

In essence, the CAS value exists so that that a client can 'hold' the CAS value for a item ID that it knows, and only updatethe item if the CAS has not changed. Hence, Compare And Swap (CAS). In a multi-client environment it's designed toprevent one client changing the value of an item when another client may have already updated it.

Unfortunately there's no way to lock items; individual operations (set, for example) are atomic, but multiple operations arenot, and this is what CAS is designed to protect against. To stop you changing a value that has changed since the last GET.

In order to demonstrate this situation, add the bold lines to the processInput method to allow a way to perform a CAS op-eration and see what happens if two copies of the program are run at the same time:

} else if (input.startsWith("/who")) {

System.out.println("Users connected: " + client.get("CurrentUsers")); } else if (input.startsWith("/cas")) { runCasTest(); } else {

Now create the runCasTest() method at the bottom of the class:

private void runCasTest() {

System.out.println("Testing a CAS operation."); CASValue<Object> cas = client.gets("CasTest");

if (cas == null) { // Must create it first System.out.println("Creating CasTest value."); client.set("CasTest", 120, "InitialValue"); return; }

System.out.println("CAS for CasTest = "+cas.getCas()); System.out.println("Sleeping for 10 seconds."); try { Thread.sleep(10000); } catch (InterruptedException e) { }

CASResponse response = client.cas("CasTest", cas.getCas(), "ReplacedValue"); if (response.equals(CASResponse.OK)) { System.out.println("OK response."); } else if (response.equals(CASResponse.EXISTS)) { System.out.println("EXISTS response."); } else if (response.equals(CASResponse.NOT_FOUND)) { System.out.println("NOT_FOUND response."); }

cas = client.gets("CasTest"); System.err.println("CAS after = "+cas.getCas()); }

The first time the test is run (by typing "/cas" while the application is running) the gets() method will returnnull, so it will just set the CasTest key to "InitialValue" and return. The second time the test is run it will get aCASValue<Object> instance from the gets() method, print out its value, and then sleep for 10 seconds. Then aftersleeping, the code performs a client.cas() method call to replace the value.

Page 13: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 13/16

Membase and Java Tutorial

13

If you run this in two different windows you may see output something like the following if you time things just right:

/casTesting a CAS operation.Creating CasTest value./casTesting a CAS operation.CAS for CasTest = 74Sleeping for 10 seconds.OK response.CAS after = 75/casTesting a CAS operation.CAS for CasTest = 75Sleeping for 10 seconds.EXISTS response.CAS after = 79

In the second copy of the application, the output would look something like this:

/casTesting a CAS operation.CAS for CasTest = 75Sleeping for 10 seconds.OK response.CAS after = 79

What you see is that when the CAS is 75, the second client modifies the value before the first client is done sleeping. In-stead of getting an OK response, that client gets an EXISTS response indicating that a change has been made before it hada chance to do so, so its client.cas() operation failed, and the code would have to handle this situation to rectify the situa-tion.

Locking is not an option if you want to have an operational distributed database. Locking causes contention and complexi-ty. Being able to quickly detect when a value has been overwritten without having to hold a lock is a simple solution to theproblem. You will be able to write code to handle the situation either by returning an error to the user, or retrying the oper-ation after obtaining another CAS value.

11. Using vbucketsOne of the newest features of the spymemcached client library is called vbucket support. The vBucket algorithm allowsMembase to automatically connect clients to the data they need even if servers are being rearranged, taken offline, and soon. It is an indirection layer on top of buckets in Membase that are transparent to clients. According to an article writtenby Dustin Sallings the basic requirements that led to the development of vbuckets are as follows:

a. Never service a request on the wrong server.

b. Allow scaling up and down at will.

c. Servers refuse commands that they should not service, but

d. Servers still do not know about each other.

e. We can hand data sets from one server another atomically, but

f. There are no temporal constraints.

g. Consistency is guaranteed.

h. Absolutely no network overhead is introduced in the normal case.

If you want to know more about vbuckets, be sure to read Dustin's article.

Page 14: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 14/16

Membase and Java Tutorial

14

You have been using a pre-release version of the spymemcached client library to complete the rest of this tutorial, and in-side it a new NodeLocator implementation exists that uses vbucket hashing. It is designed to automatically adjust to thechanging topology of your Membase cluster at runtime.

All you need to start using this functionality is to use a new MemcachedClient constructor that allows you to pass in alist of base URIs, and the bucket name and password. Replace the first three lines of the connect() method you wrote

earlier with the following lines:URI base = new URI(String.format("http://%s:8091/pools", serverAddress);List<URI> baseURIs = new List<URI>();baseURIs.add(base);client = new MemcachedClient(baseURIs, "private","private", "private");

Compile and run the application:

$ mvn assembly:assembly$ java -jar target\membasetutorial-exe.jar serverhost

Replace serverhost with the name or IP address of your server, you won't need the port this time. You will see somethinglike the following output:

INFO: Connection state changed for sun.nio.ch.SelectionKeyImpl@16930e2Connection established with acme-ubuntu-11/10.0.0.57:11210Reconnected count: 119-May-2011 10:09:25 PM net.spy.memcached.auth.AuthThread$1 receivedStatusINFO: Authenticated to acme-win7/10.0.0.33:11210You are user 7.19-May-2011 10:09:25 PM net.spy.memcached.auth.AuthThread$1 receivedStatusINFO: Authenticated to acme-ubuntu-11/10.0.0.57:11210Registration succeeded.There are currently 4 connected.Enter text, or /who to see user list, or /quit to exit.

You can see that it connects to the server and automatically loads the list of all Membase servers, connects to them and au-thenticates. It uses the vbucket algorithm automatically, and no code changes to the application will be required.

12. The TAP APISometimes you need to be able to enumerate the keys in your database. This kind of functionality would have come inhandy for the tutorial application's requirement to output all of the previous messages when the client first connects to theserver. This is what the TAP API can be used for.

The spymemcached client library includes a new class called TapClient that can be used to dump all of the keys that matcha certain pattern, or even listen to the changes occurring in the Membase bucket and return any that match a pattern. Youcould use the following code to output all of the messages for the chat room:

private void tap(String serverAddress) throws Exception {

URI base = new URI(String.format("http://%s:8091/pools",serverAddress)); List<URI> uris = new LinkedList<URI>(); uris.add(base);

TapClient tapClient = new TapClient(uris, "private", "private", "private");

Operation op = tapClient.tapDump(null, "(Message:[0-9]*)", null);

while(tapClient.hasMoreMessages()) { ResponseMessage response = tapClient.getNextMessage(); if (response != null) { System.out.println(response.getKey() + " -> " + response.getValue()); } }

tapClient.shutdown();

Page 15: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 15/16

Membase and Java Tutorial

15

}

Here, you will notice that we're creating a TapClient instance in much the same way that the vbucket MemcacheClientwas being created. Then, the tapDump() method is called with a pattern that will include all of the messages stored.

Modify the run() method once more to add a call to the tap() method:

connect(serverAddress);

tap(serverAddress);

if (register()) { startMessageThread(); processInput(); unregister(); messageThread.interrupt(); }

If you compile the application and run it, you will likely see output something like the following:

Message:7 -> <User-8>: Is there anyone there?Message:8 -> <User-8>: I wonder if anyone is there?Message:6 -> <User-8>: Hello?Message:9 -> <User-8>: Goodbye.Message:7 -> <User-8>: Is there anyone there?

Message:9 -> <User-8>: Goodbye.Message:6 -> <User-8>: Hello?

What you'll notice is that the messages are all presented twice, and they are not in the correct order. This is because thereare actually two copies of the data in the database, the original and a single replica because we ran two clustered servers. Itwould stand to reason that the ordering issue is because the database is a distributed hash table, and the order of the keys isnot preserved in a hash table. You'll have to keep this in mind if you intend to use this API.

Finished Tutorial

Congratulations, you have completed this tutorial. You will find the completed tutorial source code for comparison withyour own by downloading tutorial-end.zip .

13. LicensesThis documentation and associated software is subject to the following licenses.

13.1. Documentation License

This documentation in any form, software or printed matter, contains proprietary information that is the exclusive prop-erty of Couchbase. Your access to and use of this material is subject to the terms and conditions of your Couchbase Soft-ware License and Service Agreement, which has been executed and with which you agree to comply. This document andinformation contained herein may not be disclosed, copied, reproduced, or distributed to anyone outside Couchbase with-out prior written consent of Couchbase or as specifically provided below. This document is not part of your license agree-ment nor can it be incorporated into any contractual agreement with Couchbase or its subsidiaries or affiliates.

Use of this documentation is subject to the following terms:You may create a printed copy of this documentation solely for your own personal use. Conversion to other formats is al-lowed as long as the actual content is not altered or edited in any way. You shall not publish or distribute this documenta-tion in any form or on any media, except if you distribute the documentation in a manner similar to how Couchbase dis-seminates it (that is, electronically for download on a Web site with the software) or on a CD-ROM or similar medium,provided however that the documentation is disseminated together with the software on the same medium. Any other use,such as any dissemination of printed copies or use of this documentation, in whole or in part, in another publication, re-quires the prior written consent from an authorized representative of Couchbase. Couchbase and/or its affiliates reserveany and all rights to this documentation not expressly granted above.

Page 16: Membase Sdk Java Tutorial 1.7

8/13/2019 Membase Sdk Java Tutorial 1.7

http://slidepdf.com/reader/full/membase-sdk-java-tutorial-17 16/16

Membase and Java Tutorial

16

This documentation may provide access to or information on content, products, and services from third parties. CouchbaseInc. and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to third-partycontent, products, and services. Couchbase Inc. and its affiliates will not be responsible for any loss, costs, or damages in-curred due to your access to or use of third-party content, products, or services.

The information contained herein is subject to change without notice and is not warranted to be error-free. If you find anyerrors, please report them to us in writing.