From 3cb8915101722d765410a161fe3e9516ab2fc496 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 13 Aug 2023 09:49:44 +0300 Subject: [PATCH 01/14] Reduce total allocations --- CHANGELOG.md | 12 ++++ project.clj | 2 +- src/main/clojure/aerospike_clj/bins.clj | 17 ++---- src/main/clojure/aerospike_clj/client.clj | 59 +++++++++---------- .../clojure/aerospike_clj/collections.clj | 19 ++++++ src/main/clojure/aerospike_clj/utils.clj | 14 ++++- 6 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 src/main/clojure/aerospike_clj/collections.clj diff --git a/CHANGELOG.md b/CHANGELOG.md index aa835ba..acdb982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### [3.1.0]- 2023-08-22 + +#### Added + +* Add the `aerospike-clj.collections/mapv` function, which is similar to `clojure.core/mapv`, but it's more efficient + when the input is not a Clojure sequence. + +#### Changed + +* Make the `aerospike-clj.utils.v->array` multi-arity, allowing to pass a `mapper-fn` to map the values before setting + them into the array. + ## [3.0.0] - 2023-08-03 ### Changed diff --git a/project.clj b/project.clj index 3cc0a24..d5ba70a 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject com.appsflyer/aerospike-clj "3.0.0-SNAPSHOT" +(defproject com.appsflyer/aerospike-clj "3.1.0-SNAPSHOT" :description "An Aerospike Clojure client." :url "https://github.com/AppsFlyer/aerospike-clj" :license {:name "Eclipse Public License" diff --git a/src/main/clojure/aerospike_clj/bins.clj b/src/main/clojure/aerospike_clj/bins.clj index 085702c..0da603b 100644 --- a/src/main/clojure/aerospike_clj/bins.clj +++ b/src/main/clojure/aerospike_clj/bins.clj @@ -1,7 +1,7 @@ (ns aerospike-clj.bins (:require [aerospike-clj.utils :as utils]) - (:import [com.aerospike.client Bin] - [clojure.lang IPersistentMap])) + (:import (clojure.lang IPersistentMap) + (com.aerospike.client Bin))) (def ^:private ^:const MAX_BIN_NAME_LENGTH 14) @@ -15,16 +15,10 @@ (throw (Exception. (format "%s is %s characters. Bin names have to be <= %d characters..." bin-name (.length bin-name) MAX_BIN_NAME_LENGTH)))) (Bin/asNull bin-name)) -(def ^:private x-bin-convert - (comp - (map (fn [[k v]] [k (utils/sanitize-bin-value v)])) - (map (fn [[k v]] (create-bin k v))))) - -(defn- map->multiple-bins [^IPersistentMap m] +(defn- map->multiple-bins ^"[Lcom.aerospike.client.Bin;@4fee060b" [^IPersistentMap m] (let [bin-names (keys m)] (if (utils/string-keys? bin-names) - (->> (into [] x-bin-convert m) - (utils/v->array Bin)) + (utils/v->array Bin #(create-bin (key %) (utils/sanitize-bin-value (val %)))) (throw (Exception. (format "Aerospike only accepts string values as bin names. Please ensure all keys in the map are strings.")))))) (defn data->bins @@ -33,4 +27,5 @@ [data] (if (map? data) (map->multiple-bins data) - (utils/v->array Bin [^Bin (Bin. "" (utils/sanitize-bin-value data))]))) + (doto (make-array Bin 1) + (aset 0 (Bin. "" (utils/sanitize-bin-value data)))))) diff --git a/src/main/clojure/aerospike_clj/client.clj b/src/main/clojure/aerospike_clj/client.clj index b15f6aa..fb16564 100644 --- a/src/main/clojure/aerospike_clj/client.clj +++ b/src/main/clojure/aerospike_clj/client.clj @@ -1,30 +1,31 @@ (ns aerospike-clj.client (:refer-clojure :exclude [update]) - (:require [clojure.string :as s] - [clojure.tools.logging :as log] - [promesa.core :as p] - [promesa.exec :as p-exec] - [aerospike-clj.policy :as policy] + (:require [aerospike-clj.aerospike-record :as record] [aerospike-clj.bins :as bins] - [aerospike-clj.utils :as utils] - [aerospike-clj.metrics :as metrics] [aerospike-clj.key :as as-key] [aerospike-clj.listeners] - [aerospike-clj.aerospike-record :as record] - [aerospike-clj.protocols :as pt]) - (:import (java.time Instant) - (java.util List Collection ArrayList Arrays) - (com.aerospike.client AerospikeClient Key Bin Operation BatchRead) - (com.aerospike.client.async EventLoop NioEventLoops EventLoops) + [aerospike-clj.metrics :as metrics] + [aerospike-clj.collections :as collections] + [aerospike-clj.policy :as policy] + [aerospike-clj.protocols :as pt] + [aerospike-clj.utils :as utils] + [clojure.string :as s] + [clojure.tools.logging :as log] + [promesa.core :as p] + [promesa.exec :as p-exec]) + (:import (aerospike_clj.listeners AsyncBatchListListener AsyncBatchOperateListListener AsyncDeleteListener + AsyncExistsArrayListener AsyncExistsListener AsyncInfoListener + AsyncRecordListener AsyncRecordSequenceListener AsyncWriteListener) + (com.aerospike.client BatchRecord Host Key) + (com.aerospike.client AerospikeClient BatchRead Bin Key Operation) + (com.aerospike.client.async EventLoop EventLoops NioEventLoops) (com.aerospike.client.cluster Node) - (com.aerospike.client.policy Policy BatchPolicy ClientPolicy - RecordExistsAction WritePolicy ScanPolicy - InfoPolicy) - (com.aerospike.client Key Host BatchRecord) - (aerospike_clj.listeners AsyncExistsListener AsyncDeleteListener AsyncWriteListener - AsyncInfoListener AsyncRecordListener AsyncRecordSequenceListener - AsyncBatchListListener AsyncExistsArrayListener AsyncBatchOperateListListener) (com.aerospike.client.listener BatchOperateListListener) + (com.aerospike.client.policy BatchPolicy ClientPolicy InfoPolicy + Policy RecordExistsAction ScanPolicy + WritePolicy) + (java.time Instant) + (java.util ArrayList Arrays Collection List) (java.util.concurrent Executor))) (def @@ -175,14 +176,14 @@ (get-batch [_this batch-reads conf] (let [op-future (p/deferred) start-time (System/nanoTime) - batch-reads-arr (ArrayList. ^Collection (mapv #(map->batch-read % dbns) batch-reads))] + batch-reads-arr (collections/mapv #(map->batch-read % dbns) batch-reads)] (.get ^AerospikeClient client ^EventLoop (.next ^EventLoops el) (AsyncBatchListListener. op-future) ^BatchPolicy (:policy conf) - ^List batch-reads-arr) + batch-reads-arr) (-> op-future - (p/then' #(mapv batch-record->map %) completion-executor) + (p/then' #(collections/mapv batch-record->map %) completion-executor) (p/then' (:transcoder conf identity)) (register-events client-events :read-batch nil start-time conf)))) @@ -193,7 +194,7 @@ (let [op-future (p/deferred) start-time (System/nanoTime) transcoder (:transcoder conf identity) - indices (utils/v->array Key (mapv #(pt/create-key (:index %) dbns (:set %)) indices))] + indices (utils/v->array Key indices #(pt/create-key (:index %) dbns (:set %)))] (.exists ^AerospikeClient client ^EventLoop (.next ^EventLoops el) (AsyncExistsArrayListener. op-future) @@ -342,7 +343,7 @@ (AsyncWriteListener. op-future) ^WritePolicy policy ^Key (pt/create-key index dbns set-name) - ^"[Lcom.aerospike.client.Bin;" (utils/v->array Bin (mapv bins/set-bin-as-null bin-names))) + ^"[Lcom.aerospike.client.Bin;" (utils/v->array Bin bin-names bins/set-bin-as-null)) (-> op-future (p/then' identity completion-executor) (register-events client-events :write index start-time conf)))) @@ -375,9 +376,7 @@ policy (:policy conf) batch-list (if (list? batch-records) batch-records - (->> batch-records - (utils/v->array BatchRecord) - (Arrays/asList))) + (into [] batch-records)) start-time (System/nanoTime) transcoder (:transcoder conf identity)] (.operate ^AerospikeClient client @@ -386,7 +385,7 @@ ^BatchPolicy policy ^List batch-list) (-> op-future - (p/then' (comp transcoder #(mapv batch-record->map %)) completion-executor) + (p/then' (comp transcoder #(collections/mapv batch-record->map %)) completion-executor) (register-events client-events :batch-operate nil start-time conf)))) @@ -426,7 +425,7 @@ (register-events client-events :info nil start-time conf)))) (get-nodes [_this] - (into [] (.getNodes ^AerospikeClient client))) + (Arrays/asList (.getNodes ^AerospikeClient client))) (get-cluster-stats [_this] (-> (.getClusterStats ^AerospikeClient client) diff --git a/src/main/clojure/aerospike_clj/collections.clj b/src/main/clojure/aerospike_clj/collections.clj new file mode 100644 index 0000000..0490c5f --- /dev/null +++ b/src/main/clojure/aerospike_clj/collections.clj @@ -0,0 +1,19 @@ +(ns aerospike-clj.collections + (:import (java.util ArrayList Collection Collections List) + (java.util.function Consumer))) + +(defn mapv + "Returns a new [java.util.List] containing the result of applying `mapper-fn` to each item in `col`. + Returns an unmodifiable list. + *Note*: This will usually be faster than `(mapv mapper-fn col)` because: + - This function allocates a new [java.util.List] in the exactly `(.size col)` size and then + fills it with the mapped values. + - If the underlying collection is not a Clojure sequence, then `mapv` will first convert it + to a Clojure sequence and then map over it. This function will not do that." + ^List [mapper-fn ^Collection col] + (let [res (ArrayList. (.size col))] + (.forEach col + (reify Consumer + (accept [_ item] + (.add res (mapper-fn item))))) + (Collections/unmodifiableList res))) diff --git a/src/main/clojure/aerospike_clj/utils.clj b/src/main/clojure/aerospike_clj/utils.clj index 0ba213e..21bf82f 100644 --- a/src/main/clojure/aerospike_clj/utils.clj +++ b/src/main/clojure/aerospike_clj/utils.clj @@ -39,8 +39,18 @@ (defn v->array "An optimized way to convert vectors into Java arrays of type `clazz`." - [clazz v] - (.toArray ^Collection v ^"[Ljava.lang.Object;" (make-array clazz (count v)))) + ([clazz ^Collection v] + (.toArray v ^"[Ljava.lang.Object;" (make-array clazz 0))) + ([clazz ^Collection v mapper-fn] + (let [size (.size v) + res (make-array clazz size)] + (loop [i (int 0) + iterator (.iterator v)] + (when (and (< i size) + (.hasNext iterator)) + (aset res i (mapper-fn (.next iterator))) + (recur (unchecked-inc-int i)))) + res))) (defn vectorize "convert a single value to a vector or any collection to the equivalent vector. From 3aa27b283287ba7a1dd9f822b7439ca3d98e92ec Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 13 Aug 2023 09:51:50 +0300 Subject: [PATCH 02/14] Fix lint warnings, update PR number --- CHANGELOG.md | 1 + src/main/clojure/aerospike_clj/client.clj | 10 +++++----- src/main/clojure/aerospike_clj/collections.clj | 2 +- src/main/clojure/aerospike_clj/utils.clj | 8 ++++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acdb982..eb2f658 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -213,6 +213,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [A complete list of all java client related changes](https://www.aerospike.com/download/client/java/notes.html) +[3.1.0]: https://github.com/AppsFlyer/aerospike-clj/pull/68 [3.0.0]: https://github.com/AppsFlyer/aerospike-clj/pull/62 [2.0.7]: https://github.com/AppsFlyer/aerospike-clj/pull/64 diff --git a/src/main/clojure/aerospike_clj/client.clj b/src/main/clojure/aerospike_clj/client.clj index fb16564..6ea6802 100644 --- a/src/main/clojure/aerospike_clj/client.clj +++ b/src/main/clojure/aerospike_clj/client.clj @@ -2,10 +2,10 @@ (:refer-clojure :exclude [update]) (:require [aerospike-clj.aerospike-record :as record] [aerospike-clj.bins :as bins] + [aerospike-clj.collections :as collections] [aerospike-clj.key :as as-key] [aerospike-clj.listeners] [aerospike-clj.metrics :as metrics] - [aerospike-clj.collections :as collections] [aerospike-clj.policy :as policy] [aerospike-clj.protocols :as pt] [aerospike-clj.utils :as utils] @@ -25,7 +25,7 @@ Policy RecordExistsAction ScanPolicy WritePolicy) (java.time Instant) - (java.util ArrayList Arrays Collection List) + (java.util Arrays List) (java.util.concurrent Executor))) (def @@ -176,14 +176,14 @@ (get-batch [_this batch-reads conf] (let [op-future (p/deferred) start-time (System/nanoTime) - batch-reads-arr (collections/mapv #(map->batch-read % dbns) batch-reads)] + batch-reads-arr (collections/map #(map->batch-read % dbns) batch-reads)] (.get ^AerospikeClient client ^EventLoop (.next ^EventLoops el) (AsyncBatchListListener. op-future) ^BatchPolicy (:policy conf) batch-reads-arr) (-> op-future - (p/then' #(collections/mapv batch-record->map %) completion-executor) + (p/then' #(collections/map batch-record->map %) completion-executor) (p/then' (:transcoder conf identity)) (register-events client-events :read-batch nil start-time conf)))) @@ -385,7 +385,7 @@ ^BatchPolicy policy ^List batch-list) (-> op-future - (p/then' (comp transcoder #(collections/mapv batch-record->map %)) completion-executor) + (p/then' (comp transcoder #(collections/map batch-record->map %)) completion-executor) (register-events client-events :batch-operate nil start-time conf)))) diff --git a/src/main/clojure/aerospike_clj/collections.clj b/src/main/clojure/aerospike_clj/collections.clj index 0490c5f..16fefdf 100644 --- a/src/main/clojure/aerospike_clj/collections.clj +++ b/src/main/clojure/aerospike_clj/collections.clj @@ -2,7 +2,7 @@ (:import (java.util ArrayList Collection Collections List) (java.util.function Consumer))) -(defn mapv +(defn map "Returns a new [java.util.List] containing the result of applying `mapper-fn` to each item in `col`. Returns an unmodifiable list. *Note*: This will usually be faster than `(mapv mapper-fn col)` because: diff --git a/src/main/clojure/aerospike_clj/utils.clj b/src/main/clojure/aerospike_clj/utils.clj index 21bf82f..b57bebf 100644 --- a/src/main/clojure/aerospike_clj/utils.clj +++ b/src/main/clojure/aerospike_clj/utils.clj @@ -42,10 +42,10 @@ ([clazz ^Collection v] (.toArray v ^"[Ljava.lang.Object;" (make-array clazz 0))) ([clazz ^Collection v mapper-fn] - (let [size (.size v) - res (make-array clazz size)] - (loop [i (int 0) - iterator (.iterator v)] + (let [size (.size v) + res (make-array clazz size) + iterator (.iterator v)] + (loop [i (int 0)] (when (and (< i size) (.hasNext iterator)) (aset res i (mapper-fn (.next iterator))) From 7e227663404bedeb5d03559109a3ed28417c9e6e Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 13 Aug 2023 10:16:56 +0300 Subject: [PATCH 03/14] Optimize `map->multiple-bins` --- CHANGELOG.md | 8 ++++++- src/main/clojure/aerospike_clj/bins.clj | 21 +++++++++++++------ src/main/clojure/aerospike_clj/client.clj | 10 ++++----- .../clojure/aerospike_clj/collections.clj | 2 +- src/main/clojure/aerospike_clj/utils.clj | 7 ++++--- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb2f658..080dacd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,13 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #### Added -* Add the `aerospike-clj.collections/mapv` function, which is similar to `clojure.core/mapv`, but it's more efficient +* Add the `aerospike-clj.collections/->map` function, which is similar to `clojure.core/mapv`, but it's more efficient when the input is not a Clojure sequence. #### Changed * Make the `aerospike-clj.utils.v->array` multi-arity, allowing to pass a `mapper-fn` to map the values before setting them into the array. +* Optimize the `aerospike-clj.utils/v->array` function by `java.util.Collection#toArray` with a 0-length array, this + will force the implementation to use the more performant `java.util.Arrays.copyOf`. + +#### Deprecated + +* Deprecate `aerospike-clj.utils/string-keys?`. ## [3.0.0] - 2023-08-03 diff --git a/src/main/clojure/aerospike_clj/bins.clj b/src/main/clojure/aerospike_clj/bins.clj index 0da603b..a4ad7c4 100644 --- a/src/main/clojure/aerospike_clj/bins.clj +++ b/src/main/clojure/aerospike_clj/bins.clj @@ -15,11 +15,20 @@ (throw (Exception. (format "%s is %s characters. Bin names have to be <= %d characters..." bin-name (.length bin-name) MAX_BIN_NAME_LENGTH)))) (Bin/asNull bin-name)) -(defn- map->multiple-bins ^"[Lcom.aerospike.client.Bin;@4fee060b" [^IPersistentMap m] - (let [bin-names (keys m)] - (if (utils/string-keys? bin-names) - (utils/v->array Bin #(create-bin (key %) (utils/sanitize-bin-value (val %)))) - (throw (Exception. (format "Aerospike only accepts string values as bin names. Please ensure all keys in the map are strings.")))))) +(defn- map->multiple-bins ^"[Lcom.aerospike.client.Bin;" [^IPersistentMap m] + (let [size (.count m) + iterator (.iterator m) + res (make-array Bin size)] + (loop [i (int 0)] + (when (and (< i size) + (.hasNext iterator)) + (let [entry (.next iterator) + key-entry (key entry)] + (when-not (string? key-entry) + (throw (Exception. (format "Aerospike only accepts string values as bin names. Please ensure all keys in the map are strings.")))) + (aset res i (create-bin key-entry (utils/sanitize-bin-value (val entry)))) + (recur (unchecked-inc-int i))))) + res)) (defn data->bins "Function to identify whether `data` will be stored as a single or multiple bin record. @@ -27,5 +36,5 @@ [data] (if (map? data) (map->multiple-bins data) - (doto (make-array Bin 1) + (doto ^"[Ljava.lang.Object;" (make-array Bin 1) (aset 0 (Bin. "" (utils/sanitize-bin-value data)))))) diff --git a/src/main/clojure/aerospike_clj/client.clj b/src/main/clojure/aerospike_clj/client.clj index 6ea6802..7b282c2 100644 --- a/src/main/clojure/aerospike_clj/client.clj +++ b/src/main/clojure/aerospike_clj/client.clj @@ -176,14 +176,14 @@ (get-batch [_this batch-reads conf] (let [op-future (p/deferred) start-time (System/nanoTime) - batch-reads-arr (collections/map #(map->batch-read % dbns) batch-reads)] + batch-reads-arr (collections/->map #(map->batch-read % dbns) batch-reads)] (.get ^AerospikeClient client ^EventLoop (.next ^EventLoops el) (AsyncBatchListListener. op-future) ^BatchPolicy (:policy conf) batch-reads-arr) (-> op-future - (p/then' #(collections/map batch-record->map %) completion-executor) + (p/then' #(collections/->map batch-record->map %) completion-executor) (p/then' (:transcoder conf identity)) (register-events client-events :read-batch nil start-time conf)))) @@ -194,7 +194,7 @@ (let [op-future (p/deferred) start-time (System/nanoTime) transcoder (:transcoder conf identity) - indices (utils/v->array Key indices #(pt/create-key (:index %) dbns (:set %)))] + indices (utils/v->array Key #(pt/create-key (:index %) dbns (:set %)) indices)] (.exists ^AerospikeClient client ^EventLoop (.next ^EventLoops el) (AsyncExistsArrayListener. op-future) @@ -343,7 +343,7 @@ (AsyncWriteListener. op-future) ^WritePolicy policy ^Key (pt/create-key index dbns set-name) - ^"[Lcom.aerospike.client.Bin;" (utils/v->array Bin bin-names bins/set-bin-as-null)) + ^"[Lcom.aerospike.client.Bin;" (utils/v->array Bin bins/set-bin-as-null bin-names)) (-> op-future (p/then' identity completion-executor) (register-events client-events :write index start-time conf)))) @@ -385,7 +385,7 @@ ^BatchPolicy policy ^List batch-list) (-> op-future - (p/then' (comp transcoder #(collections/map batch-record->map %)) completion-executor) + (p/then' (comp transcoder #(collections/->map batch-record->map %)) completion-executor) (register-events client-events :batch-operate nil start-time conf)))) diff --git a/src/main/clojure/aerospike_clj/collections.clj b/src/main/clojure/aerospike_clj/collections.clj index 16fefdf..7223751 100644 --- a/src/main/clojure/aerospike_clj/collections.clj +++ b/src/main/clojure/aerospike_clj/collections.clj @@ -2,7 +2,7 @@ (:import (java.util ArrayList Collection Collections List) (java.util.function Consumer))) -(defn map +(defn ->map "Returns a new [java.util.List] containing the result of applying `mapper-fn` to each item in `col`. Returns an unmodifiable list. *Note*: This will usually be faster than `(mapv mapper-fn col)` because: diff --git a/src/main/clojure/aerospike_clj/utils.clj b/src/main/clojure/aerospike_clj/utils.clj index b57bebf..0ffd0ed 100644 --- a/src/main/clojure/aerospike_clj/utils.clj +++ b/src/main/clojure/aerospike_clj/utils.clj @@ -21,7 +21,8 @@ (= bin-names [""])) (defn string-keys? - "Predicate function to determine whether all keys provided for bins are strings." + {:docstring "Predicate function to determine whether all keys provided for bins are strings." + :deprecated "3.1.0"} [bin-names] (every? string? bin-names)) @@ -41,9 +42,9 @@ "An optimized way to convert vectors into Java arrays of type `clazz`." ([clazz ^Collection v] (.toArray v ^"[Ljava.lang.Object;" (make-array clazz 0))) - ([clazz ^Collection v mapper-fn] + ([clazz mapper-fn ^Collection v] (let [size (.size v) - res (make-array clazz size) + res ^"[Ljava.lang.Object;" (make-array clazz size) iterator (.iterator v)] (loop [i (int 0)] (when (and (< i size) From 47d3aa8fb002bbb9919098d9ac4a84f4b54e09b8 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 13 Aug 2023 10:20:53 +0300 Subject: [PATCH 04/14] Correct type hint --- src/main/clojure/aerospike_clj/bins.clj | 4 ++-- src/main/clojure/aerospike_clj/client.clj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/clojure/aerospike_clj/bins.clj b/src/main/clojure/aerospike_clj/bins.clj index a4ad7c4..572bc75 100644 --- a/src/main/clojure/aerospike_clj/bins.clj +++ b/src/main/clojure/aerospike_clj/bins.clj @@ -33,8 +33,8 @@ (defn data->bins "Function to identify whether `data` will be stored as a single or multiple bin record. Only Clojure maps will default to multiple bins. Nested data structures are supported." - [data] + ^"[Lcom.aerospike.client.Bin;" [data] (if (map? data) (map->multiple-bins data) - (doto ^"[Ljava.lang.Object;" (make-array Bin 1) + (doto ^"[Lcom.aerospike.client.Bin;" (make-array Bin 1) (aset 0 (Bin. "" (utils/sanitize-bin-value data)))))) diff --git a/src/main/clojure/aerospike_clj/client.clj b/src/main/clojure/aerospike_clj/client.clj index 7b282c2..68e3fa5 100644 --- a/src/main/clojure/aerospike_clj/client.clj +++ b/src/main/clojure/aerospike_clj/client.clj @@ -104,7 +104,7 @@ (AsyncWriteListener. op-future) ^WritePolicy policy ^Key (pt/create-key index dbns set-name) - ^"[Lcom.aerospike.client.Bin;" bins) + bins) (register-events op-future client-events :write index start-time conf))) (deftype SimpleAerospikeClient [client From e70be79be8c12cd572acf7128e9d09ec13db1208 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 13 Aug 2023 10:55:47 +0300 Subject: [PATCH 05/14] No int casting --- src/main/clojure/aerospike_clj/bins.clj | 4 ++-- src/main/clojure/aerospike_clj/utils.clj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/clojure/aerospike_clj/bins.clj b/src/main/clojure/aerospike_clj/bins.clj index 572bc75..f80be0b 100644 --- a/src/main/clojure/aerospike_clj/bins.clj +++ b/src/main/clojure/aerospike_clj/bins.clj @@ -19,7 +19,7 @@ (let [size (.count m) iterator (.iterator m) res (make-array Bin size)] - (loop [i (int 0)] + (loop [i 0] (when (and (< i size) (.hasNext iterator)) (let [entry (.next iterator) @@ -27,7 +27,7 @@ (when-not (string? key-entry) (throw (Exception. (format "Aerospike only accepts string values as bin names. Please ensure all keys in the map are strings.")))) (aset res i (create-bin key-entry (utils/sanitize-bin-value (val entry)))) - (recur (unchecked-inc-int i))))) + (recur (inc i))))) res)) (defn data->bins diff --git a/src/main/clojure/aerospike_clj/utils.clj b/src/main/clojure/aerospike_clj/utils.clj index 0ffd0ed..601fd3e 100644 --- a/src/main/clojure/aerospike_clj/utils.clj +++ b/src/main/clojure/aerospike_clj/utils.clj @@ -46,11 +46,11 @@ (let [size (.size v) res ^"[Ljava.lang.Object;" (make-array clazz size) iterator (.iterator v)] - (loop [i (int 0)] + (loop [i 0] (when (and (< i size) (.hasNext iterator)) (aset res i (mapper-fn (.next iterator))) - (recur (unchecked-inc-int i)))) + (recur (inc i)))) res))) (defn vectorize From 9229ca196f04866b14d5442648f7092ab2cd4656 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 13 Aug 2023 15:31:03 +0300 Subject: [PATCH 06/14] PR #68 code review comments [1] --- CHANGELOG.md | 2 +- project.clj | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 080dacd..95a7648 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #### Changed -* Make the `aerospike-clj.utils.v->array` multi-arity, allowing to pass a `mapper-fn` to map the values before setting +* Make the `aerospike-clj.utils/v->array` multi-arity, allowing to pass a `mapper-fn` to map the values before setting them into the array. * Optimize the `aerospike-clj.utils/v->array` function by `java.util.Collection#toArray` with a 0-length array, this will force the implementation to use the more performant `java.util.Arrays.copyOf`. diff --git a/project.clj b/project.clj index d5ba70a..d735bd6 100644 --- a/project.clj +++ b/project.clj @@ -23,7 +23,8 @@ [cheshire "5.11.0"] [tortue/spy "2.14.0"] [com.fasterxml.jackson.core/jackson-databind "2.11.2"] - [clj-kondo "2022.04.25"]] + [clj-kondo "2022.04.25"] + [com.clojure-goes-fast/clj-java-decompiler "0.3.4"]] :eftest {:multithread? false :report eftest.report.junit/report :report-to-file "target/junit.xml"} From 6446c838224c4360b7e7ef439373fc48047d0569 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 13 Aug 2023 15:35:17 +0300 Subject: [PATCH 07/14] Rename `->map` to `->list` --- src/main/clojure/aerospike_clj/client.clj | 6 +++--- src/main/clojure/aerospike_clj/collections.clj | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/clojure/aerospike_clj/client.clj b/src/main/clojure/aerospike_clj/client.clj index 68e3fa5..7345ea7 100644 --- a/src/main/clojure/aerospike_clj/client.clj +++ b/src/main/clojure/aerospike_clj/client.clj @@ -176,14 +176,14 @@ (get-batch [_this batch-reads conf] (let [op-future (p/deferred) start-time (System/nanoTime) - batch-reads-arr (collections/->map #(map->batch-read % dbns) batch-reads)] + batch-reads-arr (collections/->list #(map->batch-read % dbns) batch-reads)] (.get ^AerospikeClient client ^EventLoop (.next ^EventLoops el) (AsyncBatchListListener. op-future) ^BatchPolicy (:policy conf) batch-reads-arr) (-> op-future - (p/then' #(collections/->map batch-record->map %) completion-executor) + (p/then' #(collections/->list batch-record->map %) completion-executor) (p/then' (:transcoder conf identity)) (register-events client-events :read-batch nil start-time conf)))) @@ -385,7 +385,7 @@ ^BatchPolicy policy ^List batch-list) (-> op-future - (p/then' (comp transcoder #(collections/->map batch-record->map %)) completion-executor) + (p/then' (comp transcoder #(collections/->list batch-record->map %)) completion-executor) (register-events client-events :batch-operate nil start-time conf)))) diff --git a/src/main/clojure/aerospike_clj/collections.clj b/src/main/clojure/aerospike_clj/collections.clj index 7223751..5ef77d0 100644 --- a/src/main/clojure/aerospike_clj/collections.clj +++ b/src/main/clojure/aerospike_clj/collections.clj @@ -2,7 +2,7 @@ (:import (java.util ArrayList Collection Collections List) (java.util.function Consumer))) -(defn ->map +(defn ->list "Returns a new [java.util.List] containing the result of applying `mapper-fn` to each item in `col`. Returns an unmodifiable list. *Note*: This will usually be faster than `(mapv mapper-fn col)` because: From 6e77a1e65dffa77ca4a3847f7dee0dc7b94f4117 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Tue, 22 Aug 2023 16:54:01 +0300 Subject: [PATCH 08/14] Fix after rebase --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95a7648..f26c912 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -220,6 +220,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [A complete list of all java client related changes](https://www.aerospike.com/download/client/java/notes.html) [3.1.0]: https://github.com/AppsFlyer/aerospike-clj/pull/68 + [3.0.0]: https://github.com/AppsFlyer/aerospike-clj/pull/62 [2.0.7]: https://github.com/AppsFlyer/aerospike-clj/pull/64 From 9909eaadcb9cbacb372d12aa5172422b32e6b265 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Tue, 22 Aug 2023 17:31:42 +0300 Subject: [PATCH 09/14] Reword the CHANGELOG --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f26c912..26c569a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,19 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -### [3.1.0]- 2023-08-22 +### [3.1.0] - 2023-08-22 #### Added -* Add the `aerospike-clj.collections/->map` function, which is similar to `clojure.core/mapv`, but it's more efficient +* Add the `aerospike-clj.collections/->list` function, which is similar to `clojure.core/mapv`, but it's more efficient when the input is not a Clojure sequence. #### Changed * Make the `aerospike-clj.utils/v->array` multi-arity, allowing to pass a `mapper-fn` to map the values before setting them into the array. -* Optimize the `aerospike-clj.utils/v->array` function by `java.util.Collection#toArray` with a 0-length array, this - will force the implementation to use the more performant `java.util.Arrays.copyOf`. +* Optimize the `aerospike-clj.utils/v->array` function by calling `java.util.Collection#toArray` with a 0-length array, + this will force the implementation to use the more performant `java.util.Arrays.copyOf`. #### Deprecated From 84c494e690fba885c3a3d556c857249ada8fd989 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Thu, 24 Aug 2023 09:49:09 +0300 Subject: [PATCH 10/14] Add type hint --- src/main/clojure/aerospike_clj/bins.clj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/clojure/aerospike_clj/bins.clj b/src/main/clojure/aerospike_clj/bins.clj index f80be0b..0d865b5 100644 --- a/src/main/clojure/aerospike_clj/bins.clj +++ b/src/main/clojure/aerospike_clj/bins.clj @@ -3,6 +3,8 @@ (:import (clojure.lang IPersistentMap) (com.aerospike.client Bin))) +(set! *warn-on-reflection* true) + (def ^:private ^:const MAX_BIN_NAME_LENGTH 14) (defn- create-bin ^Bin [^String bin-name bin-value] @@ -18,7 +20,7 @@ (defn- map->multiple-bins ^"[Lcom.aerospike.client.Bin;" [^IPersistentMap m] (let [size (.count m) iterator (.iterator m) - res (make-array Bin size)] + res ^"[Lcom.aerospike.client.Bin;" (make-array Bin size)] (loop [i 0] (when (and (< i size) (.hasNext iterator)) From 7ac38dce276f3fb7a25287961f5e652c13f48e59 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Thu, 7 Sep 2023 15:17:34 +0300 Subject: [PATCH 11/14] Cleaner document references --- src/main/clojure/aerospike_clj/collections.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/clojure/aerospike_clj/collections.clj b/src/main/clojure/aerospike_clj/collections.clj index 5ef77d0..fbdf04b 100644 --- a/src/main/clojure/aerospike_clj/collections.clj +++ b/src/main/clojure/aerospike_clj/collections.clj @@ -3,10 +3,10 @@ (java.util.function Consumer))) (defn ->list - "Returns a new [java.util.List] containing the result of applying `mapper-fn` to each item in `col`. + "Returns a new [[java.util.List]] containing the result of applying `mapper-fn` to each item in `col`. Returns an unmodifiable list. *Note*: This will usually be faster than `(mapv mapper-fn col)` because: - - This function allocates a new [java.util.List] in the exactly `(.size col)` size and then + - This function allocates a new [[java.util.ArrayList]] in the exact `(.size col)` size, and then fills it with the mapped values. - If the underlying collection is not a Clojure sequence, then `mapv` will first convert it to a Clojure sequence and then map over it. This function will not do that." From 8cde93c1a732b56ea73bba76c68527844dac1a1c Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 10 Sep 2023 11:10:30 +0300 Subject: [PATCH 12/14] Add `contents: write` permissions --- .github/workflows/ci_master.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci_master.yml b/.github/workflows/ci_master.yml index a861461..cedd3f0 100644 --- a/.github/workflows/ci_master.yml +++ b/.github/workflows/ci_master.yml @@ -1,5 +1,8 @@ name: "Push CI - master" +permissions: + contents: write + on: push: branches: From 815b7bb1b7d4c3fe5ce1b29762b96a1a5275d613 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 10 Sep 2023 11:46:01 +0300 Subject: [PATCH 13/14] PR #69 code review comments [1] --- project.clj | 2 +- src/main/clojure/aerospike_clj/utils.clj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/project.clj b/project.clj index d735bd6..095aa8d 100644 --- a/project.clj +++ b/project.clj @@ -23,7 +23,7 @@ [cheshire "5.11.0"] [tortue/spy "2.14.0"] [com.fasterxml.jackson.core/jackson-databind "2.11.2"] - [clj-kondo "2022.04.25"] + [clj-kondo "2023.09.07"] [com.clojure-goes-fast/clj-java-decompiler "0.3.4"]] :eftest {:multithread? false :report eftest.report.junit/report diff --git a/src/main/clojure/aerospike_clj/utils.clj b/src/main/clojure/aerospike_clj/utils.clj index 601fd3e..2c7925d 100644 --- a/src/main/clojure/aerospike_clj/utils.clj +++ b/src/main/clojure/aerospike_clj/utils.clj @@ -21,7 +21,7 @@ (= bin-names [""])) (defn string-keys? - {:docstring "Predicate function to determine whether all keys provided for bins are strings." + {:doc "Predicate function to determine whether all keys provided for bins are strings." :deprecated "3.1.0"} [bin-names] (every? string? bin-names)) @@ -39,7 +39,7 @@ (get reverse-boolean-replacements bin-value bin-value)) (defn v->array - "An optimized way to convert vectors into Java arrays of type `clazz`." + "An optimized way to convert [[java.util.Collection]]s into Java arrays of type `clazz`." ([clazz ^Collection v] (.toArray v ^"[Ljava.lang.Object;" (make-array clazz 0))) ([clazz mapper-fn ^Collection v] From 3be5429fb850067b8df157e767b516af670accc8 Mon Sep 17 00:00:00 2001 From: Yevgeni Tsodikov Date: Sun, 10 Sep 2023 11:59:09 +0300 Subject: [PATCH 14/14] Update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26c569a..10d3f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 them into the array. * Optimize the `aerospike-clj.utils/v->array` function by calling `java.util.Collection#toArray` with a 0-length array, this will force the implementation to use the more performant `java.util.Arrays.copyOf`. +* Add contents: write to the Push CI - master action, this should resolve the git push issues from the GitHub actions + bot. #### Deprecated @@ -219,7 +221,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [A complete list of all java client related changes](https://www.aerospike.com/download/client/java/notes.html) -[3.1.0]: https://github.com/AppsFlyer/aerospike-clj/pull/68 +[3.1.0]: https://github.com/AppsFlyer/aerospike-clj/pull/69 [3.0.0]: https://github.com/AppsFlyer/aerospike-clj/pull/62