Skip to content

Instantly share code, notes, and snippets.

@ray1729
Created March 30, 2016 21:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ray1729/e12485cec1249515126489107134a154 to your computer and use it in GitHub Desktop.
Save ray1729/e12485cec1249515126489107134a154 to your computer and use it in GitHub Desktop.
Simple time-based sliding window counter implementation in Clojure
(ns sliding-window-counter.core
(:refer-clojure :exclude [inc]))
(defprotocol ICounter
(reset [this])
(inc [this])
(value [this]))
(defrecord SlidingWindowCounter [window-size bucket-size num-buckets buckets]
ICounter
(reset [this]
(assoc this :buckets {}))
(inc [this]
(let [bucket (quot (System/currentTimeMillis) bucket-size)
buckets (update buckets bucket (fnil clojure.core/inc 0))
buckets (if (> (count buckets) num-buckets)
(let [k (apply min (keys buckets))]
(dissoc buckets k))
buckets)]
(assoc this :buckets buckets)))
(value [this]
(let [cutoff (quot (- (System/currentTimeMillis) window-size) bucket-size)]
(reduce + 0 (map val (filter #(>= (key %) cutoff) buckets))))))
(defn sliding-window-counter
[window-size num-buckets]
{:pre [(zero? (rem window-size num-buckets))]}
(let [bucket-size (quot window-size num-buckets)]
(->SlidingWindowCounter window-size bucket-size num-buckets {})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment