Skip to content

Commit

Permalink
Optimize aerospike-record/record->map (#61)
Browse files Browse the repository at this point in the history
* Optimize `aerospike-record/record->map`

1. Avoid costly `(into {} ..)`, we can use the original `(.bins record)`.
2. No need for the `keys` function, since we can rely on the previously extracted `(.bins record)`.
3. `sanitize-bin-value` and `desanitize-bin-value` don't need to transform a single item to a vector, apply a transducer on it while copying it into a second array and extract the first item from the result, this can be unrolled into a single `(get ...)` function.
4. Use `Map`'s methods to determine if it is a single bin, and avoid costly vector comparison.
  • Loading branch information
evg-tso authored Dec 1, 2022
1 parent 7713723 commit e55d4cc
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

### Unreleased

### VERSION 2.0.6
#### Changed
* Performance and memory optimization, mainly in the core `aerospike-clj.aerospike-record/record->map` function.

### VERSION 2.0.5
#### Changed
* TTLs for the mock client are now correctly mocked:
Expand Down
17 changes: 12 additions & 5 deletions src/main/clojure/aerospike_clj/aerospike_record.clj
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
(ns aerospike-clj.aerospike-record
(:require [aerospike-clj.utils :as utils])
(:import [com.aerospike.client Record]))
(:import (com.aerospike.client Record)
(java.util Map)))

(defrecord AerospikeRecord [payload ^Integer gen ^Integer ttl])

(defn- single-bin?
"Predicate function to determine whether data will be stored as a single bin or
multiple bin record."
[^Map bins]
(and (= (.size bins) 1)
(.containsKey bins "")))

(defn record->map [^Record record]
(and record
(let [bins (into {} (.bins record)) ;; converting from java.util.HashMap to a Clojure map
bin-names (keys bins)
payload (if (utils/single-bin? bin-names)
(let [bins ^Map (.bins record)
payload (if (single-bin? bins)
;; single bin record
(utils/desanitize-bin-value (get bins ""))
(utils/desanitize-bin-value (.get bins ""))
;; multiple-bin record
(reduce-kv (fn [m k v]
(assoc m k (utils/desanitize-bin-value v)))
Expand Down
15 changes: 4 additions & 11 deletions src/main/clojure/aerospike_clj/utils.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns aerospike-clj.utils
(:require [clojure.set :as set])
(:import [java.util Collection]))
(:import (java.util Collection)))

(def ^:private boolean-replacements
"For bins, Aerospike converts `true` to `1`, `false` to `0` and `nil` values are
Expand All @@ -11,12 +11,7 @@
false :false
nil :nil})

;; transducers
(def ^:private x-sanitize
(replace boolean-replacements))

(def ^:private x-desanitize
(replace (set/map-invert boolean-replacements)))
(def ^:private reverse-boolean-replacements (set/map-invert boolean-replacements))

;; predicates
(defn single-bin?
Expand All @@ -35,14 +30,12 @@
however, `true`, `false` or `nil` exist as the only value in a bin, they need to
be sanitized."
[bin-value]
(->> (into [] x-sanitize (vector bin-value))
first))
(get boolean-replacements bin-value bin-value))

(defn desanitize-bin-value
"Converts sanitized (keywordized) bin values back to their original value."
[bin-value]
(->> (into [] x-desanitize (vector bin-value))
first))
(get reverse-boolean-replacements bin-value bin-value))

(defn v->array
"An optimized way to convert vectors into Java arrays of type `clazz`."
Expand Down

0 comments on commit e55d4cc

Please sign in to comment.