Skip to content

Instantly share code, notes, and snippets.

@dottedmag
Last active Jul 22, 2019
Embed
What would you like to do?
;; Dealing with a not-very-well-designed network protocol. This protocol requires
;; a client to specify "id" in requests. These "id"s are 1 byte long, and they are
;; used to correlate requests with asynchronous responses.
;;
;; Most of the time it is known that an "id" is no longer in use (protocol specifies
;; quantity of responses the a request can receive), however some requests might produce
;; an additional spurious response later on with no documented upper bound of time.
;;
;; Hence, `free` list is LRU-sorted to minimize chances of picking up an id that will
;; receive a spurious response from a previous operation.
(def ^:private resource-id-lru
(atom {:in-use #{}
:free (into clojure.lang.PersistentQueue/EMPTY (range 1 256))}))
(defn ^:private alloc-fn [{:keys [in-use free] :as old}]
(if-not (empty? free)
{:in-use (conj in-use (peek free)) :free (pop free)}
old))
(defn ^:private free-fn [{:keys [in-use free] :as old} resource-id]
(if (contains? in-use resource-id)
{:in-use (disj in-use resource-id) :free (conj free resource-id)}
old))
(defn alloc []
(let [{:keys [free]} (swap! resource-id-lru alloc-fn)]
(if (empty? free)
(throw (ex-info "All resource IDs are in use" {})))
(peek free)))
(defn free [resource-id]
(let [{:keys [in-use]} (swap! resource-id-lru free-fn resource-id)]
(if-not (contains? in-use resource-id)
(throw (ex-info "Resource ID is not allocated" {:resource-id resource-id})))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment