Skip to content

Instantly share code, notes, and snippets.

@hideshi
Created December 29, 2013 08:10
Show Gist options
  • Save hideshi/8168521 to your computer and use it in GitHub Desktop.
Save hideshi/8168521 to your computer and use it in GitHub Desktop.
This is hash map database written in Clojure. See also: http://d.hatena.ne.jp/hideshi_o/20121123/1353698397
;mapdb.clj
(ns db.mapdb
(:use
[clojure.contrib.duck-streams :only (reader)]
[clojure.java.io :only (writer)]
[clojure.string :only (split)]
[clojure.contrib.server-socket :only (create-server close-server)]))
(def database-file "/Users/hideshi/Dev/Clojure/db/dbfile")
(def data (ref []))
(def out-of-date (ref []))
(def last-updated (atom (System/currentTimeMillis)))
(defn readdb []
(dosync
(let [d1 (map load-string (line-seq (reader database-file)))
d2 (partition-by :key (sort-by :key (sort-by :table (sort-by :updated-time > d1))))
d3 (map (fn [kys] (reduce (fn [a b] a) kys)) d2)]
(ref-set data d3))))
(defn writedb []
(with-open [w (writer database-file :append true)]
(dosync
(let [current (System/currentTimeMillis)]
(if (not (empty? @out-of-date))
(doseq [entity (filter #(> (:updated-time %) @last-updated) @out-of-date)]
(.write w (str (.toString entity) "\n"))))
(if (not (empty? @data))
(doseq [entity (filter #(> (:updated-time %) @last-updated) @data)]
(.write w (str (.toString entity) "\n"))))
(reset! last-updated current)))))
(defn select [condition]
(if (instance? java.util.regex.Pattern (second condition))
(into [] (filter
#(re-matches
(second condition)
(if (nil? ((first condition) %)) "" ((first condition) %)))
@data))
(into [] (filter
#(= (if (nil? ((first condition) %)) "" ((first condition) %))
(second condition))
@data))))
(defn insert [entity]
(dosync
(let [d (filter #(not (and (= (:table entity) (:table %)) (= (:key entity) (:key %)))) @data)
o (filter #(and (= (:table entity) (:table %)) (= (:key entity) (:key %))) @data)
e (conj entity [:updated-time (System/currentTimeMillis)])]
(if (not (empty? o)) (alter out-of-date into o))
(ref-set data (conj d e)))
(str "inserted:" entity)))
(def port 3333)
(def server (ref nil))
(defn dbserver [in out]
(binding [*ns* (find-ns 'db.mapdb)]
(let [buf (make-array Byte/TYPE 256)]
(loop []
(let [size (.read in buf)]
(when (not= size -1)
(let [query (String. buf "UTF-8")]
(try
(let [result (eval (read-string query))
response (.getBytes (str result "\n"))
response-size (alength response)]
(.write out response 0 response-size))
(catch Exception e (prn e)))))
(recur))))))
(defn start []
(dosync
(readdb)
(ref-set server (create-server port dbserver))))
(defn stop []
(dosync
(writedb)
(close-server @server)
(ref-set data nil)
(ref-set server nil)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment