Skip to content

Commit

Permalink
version 0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
David James committed Mar 4, 2014
0 parents commit bc5fec5
Show file tree
Hide file tree
Showing 60 changed files with 57,043 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/target
/classes
/checkouts
pom.xml
pom.xml.asc
*.jar
*.class
/.lein-*
/.nrepl-port
134 changes: 134 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# kria

A Clojure client for Riak 2.0.

## Usage

To create a connection:

(defn conn-cb [asc e a] (println (if e e "connected")))
(def conn (client/connect nil "127.0.0.1" 8087 conn-cb))

The first line sets up the callback. Here is what the callback arguments mean:

* `asc` : [`AsynchronousSocketChannel`][ASC], a Java 7 NIO.2 class that
Kria uses for asynchronous IO.
* `e` : exception; `nil` if no exception.
* `a` : attachment. Generally speaking, the attachment varies based on the
API call. In this case, it will be `true` on success or `nil` if not.

Note that `nil` argument to `client/connect` creates the connection with the
system-wide default provider. If you want to pool connections, see
[`AsynchronousChannelGroup`][ACG].

[ASC]: http://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousSocketChannel.html
[ACG]: http://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousChannelGroup.html

Try a ping with:

(defn ping-cb [asc e a] (println (if e e "pong")))
(server/ping conn ping-cb)

Get server info with:

(defn info-cb [asc e a] (prn (if e e a)))
(server/info conn info-cb)

All of the above calls are asynchronous. The callback functions are for
demonstration purposes only. In practice, they will behave in application
specific ways.

## Protocol Buffer Setup

These steps only need to be run once, or each time the underlying [Riak
Protocol Buffer][riak_pb] files are updated.

Generate `resources/com/basho/riak/protobuf/*.java` files from the
files in `resources/proto/*.proto` using these commands:

mkdir -p src/java
cd resources/proto/
protoc --java_out=../../src/java riak.proto
protoc --java_out=../../src/java riak_dt.proto
protoc --java_out=../../src/java riak_kv.proto
protoc --java_out=../../src/java riak_search.proto
protoc --java_out=../../src/java riak_yokozuna.proto
cd ../..

## Compile Java Sources

Before you can run `lein repl` for the first time, run this:

lein with-profile base javac

This will compile the `src/java/**/*.java` files, making them available to the
Clojure files.

The above command only uses the `base` profile, not the `dev` profile. This
prevents `dev/user.clj` from being loaded, which requires the Java compilation
step as a prerequisite.

If you don't do this, you will likely see this error:

Caused by: java.lang.ClassNotFoundException: com.basho.riak.protobuf.RiakPB$RpbGetServerInfoResp
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)

## History

I used the [lein-protobuf] plugin at first, but stopped using it. Why?

1. The protobuf files change rarely, so the plugin seemed less necessary.
2. The plugin added complexity that I did not think I needed.
3. I wanted to understand how the the `protoc` command worked, including how
the Java classes were getting created and where they were being stored.
4. It seemed like the plugin slow down REPL start-up.

[lein-protobuf]: https://github.com/flatland/lein-protobuf
[riak_pb]: https://github.com/basho/riak_pb

## Message Terms

This section is intended for developers.

Let me introduce some definitions. The entire data structure is called the *message*. A message consists of three pieces:

* *body length* : Bytes 0 to 3. Encodes the length of the body (e.g. the rest
of the message).
* *message code* : Byte 4. See `kria.core/message-codes`.
* *payload* : Optional; Bytes 5+. Encoded using Protocol Buffers.

These three pieces can be aggregated in various ways:

1. body length + message code = header
2. message code + payload = body
3. header + payload = message
4. body length + body = message
5. body length + message code + payload = message

I go into some detail about the message components because Basho's
[terminology of a Riak Protocol Buffer message][Riak-PB] is somewhat unclear.
That documentation uses the term 'message' for both the protobuf part and the
entire data structure. This is confusing, especially when you need to be clear
about the lengths. That's why I use a separate name, 'payload', for the
protobuf component.

Hopefully my terminology is clear. If the above five points make sense to you,
then you are in good shape. I have nothing new to say, but I do want to make
sure that some things are clear.

The body length is simply the length of the body. This sounds simple, but if
you read the Riak documentation, you may get confused. It is *not* the length
of the entire message; it does not include itself in the calculation. Put
another way:

* If there is a payload, the body length will be the length of the payload
plus 1.
* If there is no payload, the length is 1.

In both cases, the 1 comes from the message code, which is one byte long.
Another related term is the *payload length*, which is (obviously, as I have
beat the horse to death) one less than the body length.

[Riak-PB]: http://docs.basho.com/riak/latest/dev/references/protocol-buffers/
24 changes: 24 additions & 0 deletions dev/user.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(ns user
(:require
[clojure.pprint :refer (pprint)]
[clojure.repl :refer :all]
[clojure.string :as str]
[clojure.test :as test]
[clojure.tools.namespace.repl :refer (refresh)]
[kria.bucket :as bucket]
[kria.client :as client]
[kria.conversions :as conv]
[kria.core :as core]
[kria.object :as object]
[kria.search :as search]
[kria.server :as server]))

(set! *warn-on-reflection* true)

(def result (atom nil))

(defn result-cb
[asc e a]
(if-not e
(reset! result a)
(.printStackTrace ^Throwable e)))
6 changes: 6 additions & 0 deletions doc/abbreviations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Coding Abbreviations
====================

* asc = AsynchronousSocketChannel
* buf = ByteBuffer
* cb = callback function
10 changes: 10 additions & 0 deletions doc/examples/bucket_get.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(defn conn-cb [asc e a] (println (if e e "connected")))
(def conn (client/connect nil "127.0.0.1" 8087 conn-cb))
(def b (conv/byte-string<-utf8-string "b1"))
(bucket/get conn b result-cb)
(pprint @result)

(-> @result
:props
:search-index
conv/utf8-string<-byte-string)
8 changes: 8 additions & 0 deletions doc/examples/bucket_set.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(defn conn-cb [asc e a] (println (if e e "connected")))
(def conn (client/connect nil "127.0.0.1" 8087 conn-cb))
(def b (conv/byte-string<-utf8-string "b1"))
(def opts {:props
{:search true
:search-index "I123"}})
(bucket/set conn b opts result-cb)
(pprint @result)
6 changes: 6 additions & 0 deletions doc/examples/object_delete.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
(defn conn-cb [asc e a] (println (if e e "connected")))
(def conn (client/connect nil "127.0.0.1" 8087 conn-cb))
(def b (conv/byte-string<-utf8-string "b1"))
(def k (conv/byte-string<-utf8-string "k02"))
(object/delete conn b k {} result-cb)
@result ; returns true even if no object is deleted
21 changes: 21 additions & 0 deletions doc/examples/object_get.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(defn conn-cb [asc e a] (println (if e e "connected")))
(def conn (client/connect nil "127.0.0.1" 8087 conn-cb))
(def b (conv/byte-string<-utf8-string "b1"))
(def k (conv/byte-string<-utf8-string "k01"))
(object/get conn b k {} result-cb)
(pprint @result)

; Possible results:

(-> @result
:content)
; []

(-> @result
:content
first ; don't use in real code*
:value
conv/utf8-string<-byte-string)
; "v01"
; * Note: don't grab the first sibling in real code.
; You need to find a way to resolve the conflict!
16 changes: 16 additions & 0 deletions doc/examples/object_put.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(defn conn-cb [asc e a] (println (if e e "connected")))
(def conn (client/connect nil "127.0.0.1" 8087 conn-cb))
(def b (conv/byte-string<-utf8-string "b1"))
(def k (conv/byte-string<-utf8-string "k01"))
(def v {:value (conv/byte-string<-utf8-string "v01")})
(object/put conn b k v {} result-cb)
(pprint @result)

; By default, `(store b k v {} cb)` does not return the body:
(:contents @result)
; []

; To return the body, use:
(object/store conn b k v {:return-body true} result-cb)
(:contents @result)
; [...]
4 changes: 4 additions & 0 deletions doc/examples/server_info.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(defn conn-cb [asc e a] (println (if e e "connected")))
(def conn (client/connect nil "127.0.0.1" 8087 conn-cb))
(server/info conn result-cb)
(pprint @result)
4 changes: 4 additions & 0 deletions doc/examples/server_ping.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(defn conn-cb [asc e a] (println (if e e "connected")))
(def conn (client/connect nil "127.0.0.1" 8087 conn-cb))
(defn ping-cb [asc e a] (println (if e e "pong")))
(server/ping conn ping-cb)
14 changes: 14 additions & 0 deletions project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
(defproject kria "0.1.0"
:description "A Clojure client library for Riak 2.0. Uses Java 7 NIO.2."
:url "https://github.com/bluemont/kria"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:min-lein-version "2.0.0"
:dependencies [[org.clojure/clojure "1.6.0-alpha3"]
[com.google.protobuf/protobuf-java "2.5.0"]]
:source-paths ["src/clojure"]
:java-source-paths ["src/java"]
:javac-options ["-target" "1.7" "-source" "1.7"]
:profiles {:dev
{:source-paths ["dev"]
:dependencies [[org.clojure/tools.namespace "0.2.4"]]}})
Loading

0 comments on commit bc5fec5

Please sign in to comment.