{"id":16660445,"url":"https://github.com/killme2008/clj-xmemcached","last_synced_at":"2025-03-21T17:31:29.448Z","repository":{"id":51089865,"uuid":"2671017","full_name":"killme2008/clj-xmemcached","owner":"killme2008","description":"Memcached client for clojure. ","archived":false,"fork":false,"pushed_at":"2017-11-17T02:14:29.000Z","size":83,"stargazers_count":25,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-23T16:09:14.696Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://fnil.net/clj-xmemcached","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/killme2008.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE.html","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-10-29T14:22:55.000Z","updated_at":"2023-04-03T21:53:45.000Z","dependencies_parsed_at":"2022-08-19T16:10:39.893Z","dependency_job_id":null,"html_url":"https://github.com/killme2008/clj-xmemcached","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/killme2008%2Fclj-xmemcached","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/killme2008%2Fclj-xmemcached/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/killme2008%2Fclj-xmemcached/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/killme2008%2Fclj-xmemcached/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/killme2008","download_url":"https://codeload.github.com/killme2008/clj-xmemcached/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221817125,"owners_count":16885466,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-12T10:29:18.658Z","updated_at":"2024-10-28T10:31:24.728Z","avatar_url":"https://github.com/killme2008.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clj-xmemcached\n\nAn opensource memcached client for clojure wraps [xmemcached](http://fnil.net/xmemcached/). [Xmemcached](http://fnil.net/xmemcached/) is an opensource high performance memcached client for java maintained by me.\n\n##Leiningen Usage\n\nTo use clj-xmemcached,add:\n\n```clojure\n\t[clj-xmemcached \"0.4.0\"]\n```\nto your project.clj.\n\n##API docs\n\n[clj-xmemcached APIs](http://fnil.net/docs/clj-xmemcached/)\n\n## Usage\n\n### Client\n```clj\n    (require '[clj-xmemcached.core :as xm])\n\t(def client (xm/memcached \"host:port\"))\n\t(def client (xm/memcached \"host1:port1 host2:port2\" :protocol :binary))\n```\nWe create a memcached client using text protocol by default,but we can create a client using binary protocol.\n\nAlso,we can create a client using consistent hash and binary protocol:\n```clj\n\t(def client (xm/memcached \"host1:port1 host2:port2\" :protocol :binary :hash :consistent))\n```\nAll valid options:\n\n\t :protocol  Protocol to talk with memcached,a keyword in :text,:binary or :kestrel,default is text.\n     :hash  Hash algorithm,a keyword in  :consistent, :standard or :php, default is standard hash.\n     :pool  Connection pool size,default is 1,it's a recommended value.\n     session-locator memcached connection locator,default is created based on :hash algorithm value.\n     :sanitize-keys  Whether to sanitize keys before operation,default is false.\n     :reconnect  Whether to reconnect when connections are disconnected,default is true.\n     :heartbeat  Whether to do heartbeating when connections are idle,default is true.\n     :timeout  Operation timeout in milliseconds,default is five seconds.\n     :transcoder Transcoder to encode/decode data. For example, clj-json-transcoder.\n     :name  A name to define a memcached client instance\n     :selector-pool-size  Reactor pool size for every client instance, it's computed based on CPUs number by default.\"\n\n### Store items\n```clj\n\t(xm/with-client client\n\t    (xm/set \"key1\" \"dennis\")\n        (xm/set \"key2\" \"dennis\" 1)\n        (xm/add \"key3\" \"dennis\")\n\t\t;;touch the key3 expire timeout to 3 seconds.\n\t\t(xm/touch \"key3\" 2))\n```\nUse `with-client` macro to bind the client for following operations.\nThe value `100` in `set` is the expire timeout for the item in seconds.Storing item functions include `set`,`add`,`replace`,`touch`,`append` and `prepend`.\n\nUnless you need the added flexibility of specifying the client for each request,you can save some typing with a little macro:\n\n```clj\n\t(defmacro wxm\n\t    [\u0026 body]\n\t    `(xm/with-client client ~@body))\n```\n\nIf you have only one client in your application, you can set the global client by:\n```clj\n\t(xm/set-client! client)\n```\nThen all the following requests will use the global client by default,except you bind another client using `with-client` macro.\n\n### Get items\n```clj\n    ;;get k1 k2 k3...\n    (wxm\n\t\t(xm/get \"key1\")\n\t\t(xm/get \"key1\" \"key2\" \"key3\")\n\t\t(xm/gets \"key1\"))\n```\nUsing `get` to retrieve items from memcached.You can retrieve many items at one time by bulk getting,but it's result is a `java.util.HashMap`.\n`gets` returns a clojure map contains cas and value,for example:\n```clj\n\t  {:value \"hello,dennis zhuang\", :cas 396}\n```\n### Increase/Decrease numbers\n```clj\n\t;;incr/decr key delta init-value\n\t(wxm\n\t\t(xm/incr \"num\" 1)\n\t\t(xm/decr \"num\" 1)\n\t\t(xm/incr \"num\" 1 0)\n```\nAbove codes try to increase/decrease a number in memcached with key \"num\",and if the item is not exists,then set it to zero.\n\n### Delete items\n```clj\n\t(xm/delete \"num\")\n\t;;delete with CAS in binary protocol.\n\t(xm/delete \"num\" (:cas (gets \"num\")))\n```\n### Compare and set\n```clj\n\t(xm/cas \"key\" inc)\n```\nWe use `inc` function to increase the current value in memcached and try to compare and set it at most Integer.MAX_VALUE times.\n`cas` can be called in:\n```clj\n\t (xm/cas key cas-fn max-times)\n```\nThe cas-fn is a function to return a new value,set item's new value to:\n```clj\n\t(cas-fn current-value)\n```\n\n### Distribution Lock\n\nUse memcached as a lightweight distribution lock:\n\n```clj\n\t(def counter (atom 0))\n\t(future (try-lock \"lock\" 5 (do (Thread/sleep 3000)\n\t                               (swap! counter inc))\n\t\t\t\t\t\t\t    (println \"else1\")))\n\t(future (try-lock \"lock\" 5 (do (Thread/sleep 3000)\n\t                               (swap! counter inc))\n\t\t\t\t\t\t\t    (println \"else2\")))\n\t(future (try-lock \"lock\" 5 (do (Thread/sleep 3000)\n\t                               (swap! counter inc))\n\t\t\t\t\t\t\t    (println \"else3\")))\n\n\t(Thread/sleep 4000)\n    (is (nil? (get \"lock\")))\n    (is (= 1 @counter))\n```\n\n### through macro\n\n\n```clj\n\t(through uid (get-user-from-databse uid))\n```\n\nEquals to:\n\n```clj\n\t(if-let [rt (get uid)]\n\t\trt\n\t    (let [rt (get-user-from-database uid)]\n\t\t\t(when rt\n\t\t\t\t(add uid rt 0))\n\t\t\trt))\n```\n\n\n### Shutdown\n```clj\n\t(xm/shutdown)\n```\n### Flush\n```clj\n\t(xm/flush-all)\n```\n### Statistics\n```clj\n\t(xm/stats)\n```\n\n### Get the raw XmemcachedClient instance\nBecause `memcached` function returns a delayed object,so if you want to get the raw `XmemcachedClient` instance,you have to deref it:\n```clj\n\t@client\n\t(xm/shutdown @client)\n```\n\n### Transcoders\n\nWe use [SerializationTranscoder](http://xmemcached.googlecode.com/svn/trunk/apidocs/net/rubyeye/xmemcached/transcoders/SerializingTranscoder.html) by default,it will encode/decode values using java serialization.\nBut since `0.2.2`, we provide a new transcoder `clj-json-transcoder` to encode/decode values using [clojure.data.json](https://github.com/clojure/data.json).It is suitable to integrate with other systems written in other languages.\n\nAnd we add `nippy-transcoder` in 0.2.3, it use [nippy](https://github.com/ptaoussanis/nippy) for serialization.\n\n### Example\n\nPlease see the example code in [example/demo.clj](https://github.com/killme2008/clj-xmemcached/blob/master/example/demo.clj)\n\n## Performance:\nBenchmark on my machine:\n\n\tCPU 2.3 GHz Intel Core i5\n\tMemory 8G 1333 MHz DDR3\n\tJVM options: default\n\nStart memcached by:\n\n\tmemcached -m 4096 -d\n\nBenchmark result using text protocol and 1 NIO connection:\n\n\tBenchmark set: threads=50,repeats=10000,total=500000\n\tElapsed time: 10990.256 msecs\n\tBenchmark get: threads=50,repeats=10000,total=500000\n\tElapsed time: 7768.998 msecs\n\tBenchmark set \u0026 get: threads=50,repeats=10000,total=500000\n\tElapsed time: 18445.409 msecs\n\nThat it is:\n\n    45495 sets/secs\n    64350 gets/secs\n\t27114 tps (both set and get an item in one round)\n\n\n## License\n\nCopyright (C) 2011-2020 dennis zhuang[killme2008@gmail.com]\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkillme2008%2Fclj-xmemcached","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkillme2008%2Fclj-xmemcached","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkillme2008%2Fclj-xmemcached/lists"}