{"id":20434384,"url":"https://github.com/centralnicgroup-opensource/kterl","last_synced_at":"2026-06-22T01:31:44.547Z","repository":{"id":36807460,"uuid":"41114310","full_name":"centralnicgroup-opensource/kterl","owner":"centralnicgroup-opensource","description":"kyoto tycoon erlang bindings","archived":false,"fork":false,"pushed_at":"2018-01-25T12:12:34.000Z","size":238,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-13T16:33:37.308Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/centralnicgroup-opensource.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-20T19:13:59.000Z","updated_at":"2023-01-26T15:22:56.000Z","dependencies_parsed_at":"2022-09-04T04:10:54.732Z","dependency_job_id":null,"html_url":"https://github.com/centralnicgroup-opensource/kterl","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/centralnicgroup-opensource/kterl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centralnicgroup-opensource%2Fkterl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centralnicgroup-opensource%2Fkterl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centralnicgroup-opensource%2Fkterl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centralnicgroup-opensource%2Fkterl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/centralnicgroup-opensource","download_url":"https://codeload.github.com/centralnicgroup-opensource/kterl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centralnicgroup-opensource%2Fkterl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34630770,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-21T02:00:05.568Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-11-15T08:26:20.083Z","updated_at":"2026-06-22T01:31:44.533Z","avatar_url":"https://github.com/centralnicgroup-opensource.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kterl\n\nA [Kyoto Tycoon](http://fallabs.com/kyototycoon) client for Erlang.\n\nFeatures:\n\n * 100% feature support of Kyoto Tycoon's HTTP and binary protocols.\n * Proven non-blocking protocol handler, derived from [eredis](https://github.com/wooga/eredis).\n * Easy to use and fully documented, with plenty of examples.\n * Clean, consistent, idiomatic interface.\n * OTP compliant.\n\n## Examples\n\nRetrieve and build kterl:\n\n        git clone git://github.com/rcb/kterl.git\n        cd kterl\n        make \u0026\u0026 make docs\n        erl -pa ebin/\n\nDownload and install kyoto tycoon onto your machine, and start it with\na cache tree (in-memory b+tree) database:\n\n        ktserver %\n\t\nWith ktserver now running on localhost, it's easy to start experimenting:\n\n        Eshell V5.9.1  (abort with ^G)\n        1\u003e {ok, Pid} = kterl:start_link().\n\n        =INFO REPORT==== 3-Apr-2012::14:08:25 ===\n        Attempting connection to 127.0.0.1:1978\n\n        =INFO REPORT==== 3-Apr-2012::14:08:25 ===\n        Connected to Kyoto Tycoon server at 127.0.0.1:1978\n        {ok,\u003c0.35.0\u003e}\n        2\u003e\n\n### [Set | add | replace | append | remove] records from Kyoto Server\n\nKyoto Tycoon supports the standard set of key value set/add/replace/append/remove operations. The application can pass to kterl lists or binaries as key/values.\n\n        1\u003e ok = kterl:add(Pid, \u003c\u003c\"hello\"\u003e\u003e, \u003c\u003c\"world\"\u003e\u003e).\n        ok\n        2\u003e {ok, Res} = kterl:get(Pid, \"hello\").\n        {ok, ...}\n        3\u003e kterl_result:get_value(Res).\n        \u003c\u003c\"world\"\u003e\u003e\n        4\u003e ok = kterl:replace(Pid, \"hello\", \u003c\u003c\"github\"\u003e\u003e).\n        ok\n        5\u003e kterl_result:get_value(kterl:get(Pid, \"hello\")).\n        \u003c\u003c\"github\"\u003e\u003e\n        6\u003e ok = kterl:append(Pid, \u003c\u003c\"hello\"\u003e\u003e, \u003c\u003c\"...\"\u003e\u003e).\n        ok\n        7\u003e kterl_result:get_value(kterl:get(Pid, \"hello\")).\n        \u003c\u003c\"github...\"\u003e\u003e\n        8\u003e ok = kterl:remove(Pid, \"hello\").\n        ok\n        9\u003e kterl:get(Pid, \"hello\").\n        {error,no_record}\n        10\u003e e(7).\n        {error,no_record}\n\nKyoto Tycoon supports atomic record compare-and-swap and compare-and-remove operations. See the documentation for \u003ccode\u003ekterl:cas/3\u003c/code\u003e and \u003ccode\u003ekterl:cas/4\u003c/code\u003e for further information.\n\n### Automatic value conversions\n\nAs a convenience, kterl automatically converts integer, float, or atom values to binary before storing the record. \n\n        kterl:add(Pid, \"int_key\", 12345).\n        kterl_result:get_value(kterl:get(Pid, \"int_key\")).\n        \u003c\u003c\"12345\"\u003e\u003e\n\n        kterl:add(Pid, \"float_key\", 12345.123).\n        kterl_result:get_value(kterl:get(Pid, \"float_key\")).\n        \u003c\u003c\"12345.123000\"\u003e\u003e\n\n        kterl:add(Pid, \"atom_key\", hello_world).\n        kterl_result:get_value(kterl:get(Pid, \"atom_key\")).\n        \u003c\u003c\"hello_world\"\u003e\u003e\n\n        kterl:append(Pid, \"atom_key\", 123456).\n        kterl_result:get_value(kterl:get(Pid, \"atom_key\")).\n        \u003c\u003c\"hello_world123456\"\u003e\u003e\n\n        kterl:add(Pid, \"erlang_term\", term_to_binary([hello,{1,2,3,4},\u003c\u003c\"testing\"\u003e\u003e])).\n        binary_to_term(kterl_result:get_value(kterl:get(Pid, \"erlang_term\"))).\n        [hello,{1,2,3,4},\u003c\u003c\"testing\"\u003e\u003e]\n\n### Bulk record operations, using the HTTP or binary protocol\n\nKyoto Tycoon supports bulk record set/get/remove operations through HTTP or a binary protocol. kterl supports both access methods. In this snippet, 1000 key/value pairs are added, and kterl_result:get_num() is then called on the set_bulk result to extract the number of records added by the server:\n\n        11\u003e Recs = [{\"key_\" ++ integer_to_list(N), N} || N \u003c- lists:seq(1,1000)].\n        ...\n        12\u003e {ok, Res1} = kterl:set_bulk(Pid, Recs).\n        {ok, ...}\n        13\u003e kterl_result:get_num(Res1).\n        1000\n\nHere's the binary protocol bulk set call:\n\n        14\u003e kterl:bin_set_bulk(Pid, Recs).\n        {ok, 1000}\n\nBulk retrieval is easy using the HTTP protocol...\n\n        15\u003e Keys = [Key || {Key, _} \u003c- Recs].\n        ...\n        16\u003e {ok, Res2} = kterl:get_bulk(Pid, Keys).\n        {ok,...}\n        17\u003e kterl_result:get_num(Res2).\n        1000\n        18\u003e length(kterl_result:get_records(Res2)).\n        1000\n        19\u003e hd(kterl_result:get_records(Res2)).\n        {\u003c\u003c\"key_1\"\u003e\u003e,\u003c\u003c\"1\"\u003e\u003e}\n\n... or the binary protocol:\n\n        20\u003e {ok, BinRes} = kterl:bin_get_bulk(Pid, Keys).\n        {ok, ...}\n        21\u003e length(BinRes).\n        1000\n        22\u003e Fbr = hd(BinRes).\n        {kt_bin_rec,0,1099511627775,\u003c\u003c\"key_1000\"\u003e\u003e,\u003c\u003c\"1000\"\u003e\u003e}\n        23\u003e kterl_binrec:get_key(Fbr).\n        \u003c\u003c\"key_1000\"\u003e\u003e\n        24\u003e kterl_binrec:get_value(Fbr).\n        \u003c\u003c\"1000\"\u003e\u003e\n        25\u003e kterl:bin_remove_bulk(Pid, Keys).\n        {ok, 1000}\n\nAs a convenience, the application can also pass an erlang dict() to the bulk set calls:\n        \n        D = dict:from_list([{\"key1\",\"val1\"}, {\"key2\",\"val2\"}]).\n        kterl:set_bulk(Pid, D).\n        kterl:bin_set_bulk(Pid, D).\n\n### Bulk record operations - Binary vs HTTP. Which is better?\n\nThe HTTP protocol has a richer feature set than the binary protocol. It allows the application to specify target databases with a filename or a numeric identifier, and can also interact with Kyoto Tycoon's signaling mechanisms. The primary reason to use the binary calls is performance, especially for large bulk get operations:\n\n        D = dict:from_list([{\"k_\" ++ integer_to_list(N), N} || N \u003c- lists:seq(1,10000)]).\n        {ok, 10000} = kterl:bin_set_bulk(Pid, D).\n        timer:tc(kterl,get_bulk,[Pid, dict:fetch_keys(D)]).\n        {90587, ...}\n        timer:tc(kterl,bin_get_bulk,[Pid, dict:fetch_keys(D)]).\n        {35183, ...}\n\n\n### Automatic Record expiration:\n\nKyoto Tycoon supports automatic record expiration:\n\n        kterl:add(Pid, \"exprec\", \"5..4..3..\", [{xt, 5}]).\n        kterl_result:get_value(kterl:get(Pid, \"exprec\")).\n        \u003c\u003c\"5..4..3..\"\u003e\u003e\n        timer:sleep(timer:seconds(5)).\n        kterl:get(Pid,\"exprec\").\n        {error,no_record}\n\nAs a convenience, kterl converts calendar:datetime() types when setting an expiration time:\n\n        calendar:gregorian_seconds_to_datetime(\n               20 + calendar:datetime_to_gregorian_seconds(calendar:local_time())). \n        {{2012,4,3},{22,30,35}}\n\n        XT = calendar:gregorian_seconds_to_datetime(\n               20 + calendar:datetime_to_gregorian_seconds(calendar:local_time())).\n        kterl:add(Pid, \"exprec\", \"20..19..18..\", [{xt, XT}]).\n        kterl_result:get_value(kterl:get(Pid,\"exprec\")).\n        \u003c\u003c\"20..19..18..\"\u003e\u003e\n        timer:sleep(timer:seconds(20)).\n        kterl_result:get_value(kterl:get(Pid,\"exprec\")).\n        {error,no_record}\n\nMany functions in kterl allow the application to set a record's expiration time. Please check the documentation for additional information.\n\n### Counters\n\nKyoto Tycoon records can contain a value representing a counter:\n\n        1\u003e kterl:get(Pid, \"inc_test\").\n        {error,no_record}\n        2\u003e {ok,Res} = kterl:increment(Pid, \"inc_test\", 1).\n        ...\n        3\u003e kterl_result:get_num(Res).\n        1\n        4\u003e kterl_result:get_num(kterl:increment(Pid, \"inc_test\", -2)).\n        -1\n\n### Regex matching\n\n        1\u003e {ok, Res} = kterl:match_regex(Pid, \"(^c..$|^(a|z).$)\").\n        {ok, ...}\n        2\u003e kterl_result:get_keys(Res).\n        [\u003c\u003c\"ad\"\u003e\u003e,\u003c\u003c\"ah\"\u003e\u003e,\u003c\u003c\"am\"\u003e\u003e,\u003c\u003c\"an\"\u003e\u003e,\u003c\u003c\"as\"\u003e\u003e,\u003c\u003c\"at\"\u003e\u003e,\n         \u003c\u003c\"ax\"\u003e\u003e,\u003c\u003c\"ay\"\u003e\u003e,\u003c\u003c\"cab\"\u003e\u003e,\u003c\u003c\"cad\"\u003e\u003e,\u003c\u003c\"cam\"\u003e\u003e,\u003c\u003c\"can\"\u003e\u003e,\n         \u003c\u003c\"cap\"\u003e\u003e,\u003c\u003c\"car\"\u003e\u003e,\u003c\u003c\"cat\"\u003e\u003e,\u003c\u003c\"caw\"\u003e\u003e,\u003c\u003c\"chi\"\u003e\u003e,\u003c\u003c\"cob\"\u003e\u003e,\n         \u003c\u003c\"cod\"\u003e\u003e,\u003c\u003c\"cog\"\u003e\u003e,\u003c\u003c\"con\"\u003e\u003e,\u003c\u003c\"coo\"\u003e\u003e,\u003c\u003c\"cop\"\u003e\u003e,\u003c\u003c\"cot\"\u003e\u003e,\n         \u003c\u003c\"cow\"\u003e\u003e,\u003c\u003c\"cox\"\u003e\u003e,\u003c\u003c\"coy\"\u003e\u003e,\u003c\u003c\"cry\"\u003e\u003e,\u003c\u003c...\u003e\u003e|...]\n\n### Cursors\n\nKyoto Tycoon supports database cursors. With these, an application can traverse, access, and mutate records.\n\n        1\u003e {ok, Pid} = kterl:start_link().\n        ...\n        2\u003e Cursor = kterl:cursor(Pid).\n        {kterl_cursor,1,\u003c0.35.0\u003e}\n        3\u003e kterl:cur_jump(Cursor, [{key, \"key_name\"}]).\n        ok\n        4\u003e {ok, Cres} = kterl:cur_get(Cursor).\n        ...\n        5\u003e kterl_result:get_key(Cres).\n        \u003c\u003c\"key_name\"\u003e\u003e\n        6\u003e kterl_result:get_value(Cres).\n        \u003c\u003c\"record_value\"\u003e\u003e\n\nIterating over records in a database is simple. In this example, the print_record function instructs the Kyoto Tycoon server to retrieve a record's key and value, and then automatically step the cursor to an adjacent record.\n\n        print_database(Cursor) -\u003e\n            case kterl:cur_get(Cursor, true) of\n                {ok, Res} -\u003e\n                    Key = kterl_result:get_key(Res),\n                    Value = kterl_result:get_value(Res),\n                    io:format(\"~p ~p~n\",[Key, Value]),\n                    print_database(Cursor);\n                {error, invalid_cursor} -\u003e\n                    ok\n            end.\n\n        print_forward(Cursor) -\u003e\n            ok = kterl:cur_jump(Cursor),\n            print_database(Cursor).\n\n        print_reverse(Cursor) -\u003e\n            ok = kterl:cur_jump_back(Cursor),\n            print_database(Cursor).\n\nThere are many cursor calls available: seize (get and remove), setting a record's value, removing records, and so on. Please refer to the documentation.\n\n### Much more...\n\nKyoto Tycoon also supports server-side scripting, client-side signaling, and much more. Please review the documentation for additional information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcentralnicgroup-opensource%2Fkterl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcentralnicgroup-opensource%2Fkterl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcentralnicgroup-opensource%2Fkterl/lists"}