 
 
 (defn- bytebuffer->bytes
+  "Converts a ByteBuffer to a byte array. If the ByteBuffer is backed
+  by an array, a copy of the relevant part of that array is returned.
+  Otherwise, the bytes are streamed into a byte array."
   [^ByteBuffer bb]
   (if (.hasArray bb)
     (Arrays/copyOfRange (.array bb)


;;; Session Cassandra definitions.

(def read-query
  (delay (prepared-query "SELECT data FROM ring.sessions WHERE key = ?;")))

(defn- write-query*
  [ttl]
  (prepared-query (str "UPDATE ring.sessions USING TTL " (* ttl 60 2) " SET data = ? WHERE key = ?;")))

(def write-query (memoize write-query*))

(def remove-query
  (delay (prepared-query "DELETE FROM ring.sessions WHERE key = ?;")))


(def session-consistency :one)

(defn- read-session-data
  [key]

(deftype CassandraStore [cache ttl]
  SessionStore
  (read-session [_ key]
    ;; If the key is non-nil, try the cache or if that fails, try Cassandra.
    ;; If both fail, or the key was nil, an empty session is returned.
    (or (and key
             (or (get (deref cache) key)
                 (read-session-data key)))
        {}))

  (write-session [this key data]
    ;; Create a key, if necessary.
    ;; Update the data in the database, except if it already contains a _last_db_write entry,
    ;; and the time it specifies is younger than the current time minus TTL,
    ;; and the session data has not changed within the handling of the request.
    (let [new-key (or key (str (UUID/randomUUID)))
          new-data (if-not (and (get data '_last_db_write)
                                (< (- (System/currentTimeMillis) (* ttl 60000))
                                   (data '_last_db_write))
                                (= data (read-session this key)))
                     (assoc data '_last_db_write (System/currentTimeMillis))
                     data)]
