{"_id":"fash","_rev":"87-6fac155b87ec2a988735b3c4c743a5fb","name":"fash","dist-tags":{"latest":"3.0.1"},"versions":{"0.1.0":{"name":"fash","version":"0.1.0","keywords":["consistent hasing","hashing","distributed","dynamo"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@0.1.0","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"dist":{"shasum":"4e4eddc57e16091461bd5801a92da6241cfb69a2","tarball":"https://registry.npmjs.org/fash/-/fash-0.1.0.tgz","integrity":"sha512-P1+IrfFzZ7NTIgEld9aTT6bnkDgCN0HP/0rz7rUUO7thdHrsRpXEMi71fSFj2ABygYHFF7YHxLqxcyiEBZsosQ==","signatures":[{"sig":"MEUCICzffOzr/o47CVmAXByes0mMJ+HJGpBoXW+s0Ie27+B0AiEArXLNAyp16pECLf9t06Ibnsn+aRgPOLn0C/UnGUDS3kc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","engines":{"node":">=0.6"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"bignum":"0.4.1"},"devDependencies":{"tap":"*","bunyan":"*"}},"0.1.1":{"name":"fash","version":"0.1.1","keywords":["consistent hasing","hashing","distributed","dynamo"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@0.1.1","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"dist":{"shasum":"cf49e6cf6ab0c037c85f626d7f60ef55b21bec51","tarball":"https://registry.npmjs.org/fash/-/fash-0.1.1.tgz","integrity":"sha512-G7coEgpY3KPWcLgpsNeApFjLwNP2MSOXuY3xJNa6/fW6A3ip44UemxPCcgziVRZgSvcDpxLZwL5DhYx3Mi6uqg==","signatures":[{"sig":"MEYCIQDPNp5QG7u3JR9T1QC8fofFrhfpbATueLhv3g36sxRoLgIhAMnLFm8dnUIuPHrxOGeW4oNefbg57QdPApAXdy1HFfOR","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","engines":{"node":">=0.6"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"bignum":"0.4.1"},"devDependencies":{"tap":"*","bunyan":"*"}},"1.0.0":{"name":"fash","version":"1.0.0","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.0.0","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"dist":{"shasum":"64da484a436b7cf140020568179a6dea3291a2f0","tarball":"https://registry.npmjs.org/fash/-/fash-1.0.0.tgz","integrity":"sha512-jYg7AivpWm+52Qn9GVbM5kFcTO2yAEvfB2TWojMOZUf7YdbM/lG9WIBhq0FU0Ms7kN3hhOYfB8FiISVijDBjow==","signatures":[{"sig":"MEUCIQC7+ayRynas5y5WPXrqHQ5zDX2ieNeZRgVBFksglSWB5QIgPIUuQvqBjOCTob3r0sUSqxuH4OQKGW/plC3gpQ4Ejus=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","engines":{"node":">=0.6"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.1.62","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"bignum":"0.5.4","bunyan":"*","assert-plus":"0.1.2"},"devDependencies":{"tap":"*","bunyan":"*"}},"1.1.0":{"name":"fash","version":"1.1.0","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.1.0","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"dist":{"shasum":"d2d27e140fd0f7be0bfa864070a405de939f2c95","tarball":"https://registry.npmjs.org/fash/-/fash-1.1.0.tgz","integrity":"sha512-pVFXd8caCmr/Y4jqOHCFuOTSCa+uFvT6qkc+nuoVhcShfviK9HwO1grp8Ue+7oGyDCMkm4+UjiFrTMmhci7VCA==","signatures":[{"sig":"MEUCIA+TrT0HvMg2nOudNO5mHv7xu3Q+bDVXYPU07gNFnKg6AiEA71A0R3jiTklNU2s5PX0c/rLjqTcTZuJ9Z+kU/rJhxNw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"bignum":"0.6.0","bunyan":"*","assert-plus":"0.1.2"},"devDependencies":{"tap":"*","bunyan":"*"}},"1.1.1":{"name":"fash","version":"1.1.1","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.1.1","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"dist":{"shasum":"0de03ba278539752021e667d280bd9f7cd900480","tarball":"https://registry.npmjs.org/fash/-/fash-1.1.1.tgz","integrity":"sha512-SKZEv46b98KgwVG7bCX7T7boe55tgg9bMaTv4uwCN7b10bz0GXCNFbM7AILTtV2HXc+yzxDRtK/Glm6Y0erSBg==","signatures":[{"sig":"MEQCIDKONlIc8O38nmVAyUcclTYPlOY5Nw5ZJpasJwRZeql8AiAXZfMfcGhiPdIgilxu4wDb3R79QphqS/CnOCCFLF7dLQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"bignum":"0.6.0","bunyan":"*","assert-plus":"0.1.2"},"devDependencies":{"tap":"*","bunyan":"*"}},"1.1.2":{"name":"fash","version":"1.1.2","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.1.2","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"dist":{"shasum":"09b12a47f9f50c8b45add46d58689eec9b7f193a","tarball":"https://registry.npmjs.org/fash/-/fash-1.1.2.tgz","integrity":"sha512-bF/U2/dGQnUW5MYqjwt2U8ZosYdu5EoPGIlfUeBFWZ6jbfu2lWDhF2ismDhh6UHQt+DE02HUDpKIIozNSPBCvA==","signatures":[{"sig":"MEYCIQCn4L6D40X/aq2eUwaT719CA2eAVJCyNCJ+FUbRCL29fgIhANmxDrVarO5LOILy6yoIzjqk/lEv0PmorbeAP/i4ZXDy","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"bignum":"0.6.0","bunyan":"*","assert-plus":"0.1.2"},"devDependencies":{"tap":"*","bunyan":"*"}},"1.1.3":{"name":"fash","version":"1.1.3","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.1.3","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"dist":{"shasum":"de466e732e44217adddf150f7706a7ee1094a0ca","tarball":"https://registry.npmjs.org/fash/-/fash-1.1.3.tgz","integrity":"sha512-+q6hY6+p/tGkwPQLlM95c5BFfRNYb7kbBvKaFjtDD9rx1EfBIVT3mdV0dHyxiaGyoRHSec2d8MkaOAlxCn3xUw==","signatures":[{"sig":"MEQCICatJJ2uzdJMMEVyN33rA7KlFIWc/k1lGfF6rBGHljBbAiAs+bbiMK2ubpovut8dN2CPBJmwQ8QcFLd2hEYeLQtjmg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"bignum":"0.6.0","bunyan":"*","assert-plus":"0.1.2"},"devDependencies":{"tap":"*","bunyan":"*"}},"1.1.4":{"name":"fash","version":"1.1.4","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.1.4","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"dist":{"shasum":"d839eeca6fdf2a3a25fcaff008928232a13ababf","tarball":"https://registry.npmjs.org/fash/-/fash-1.1.4.tgz","integrity":"sha512-gxe8cj3ttXJXg/JE6ledw1qpSdDCABDkomgnU/OjS+ggh6TPI5hVXoM3I/D+2ziA428CGHNJmwtSIBpH7KS+rw==","signatures":[{"sig":"MEQCICdRli8MQUz399HBY3ywKuq1hQcYajQe7QfEbjFD1PNIAiBcl3SIEvLCKjvbc4UKbcF4qzFGg/m6rHkaOfxLAerSrA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"cmdln":"1.1.1","bignum":"0.6.0","bunyan":"*","dashdash":"1.2.1","assert-plus":"0.1.2"},"devDependencies":{"tap":"*","bunyan":"*"}},"1.1.5":{"name":"fash","version":"1.1.5","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.1.5","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"dist":{"shasum":"ca933f98194d332113438e3221eed7254546e783","tarball":"https://registry.npmjs.org/fash/-/fash-1.1.5.tgz","integrity":"sha512-C6RlcWzcUnxQxEzCJ8ok/sFTNaGTDAjWH+0etHM7ADha40LrQzinfTiw7oO8y+5W3IBaGgWL3okTFaFNpBUchg==","signatures":[{"sig":"MEUCIHBw5dk2OYhmIP+fAFqqth5uwhBur0apQ55xLsgD6G+pAiEAoUrHmT+UINK5hLz0pKPmWmE/vOftSWouuCUmzDxJwJU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/tap test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.1.62","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"cmdln":"1.1.1","bignum":"0.6.0","bunyan":"*","dashdash":"1.2.1","assert-plus":"0.1.2"},"devDependencies":{"tap":"*","bunyan":"*"}},"1.2.0":{"name":"fash","version":"1.2.0","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.2.0","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"dist":{"shasum":"b33d2fcf7db1284399c4c6a41ce63a985ed73013","tarball":"https://registry.npmjs.org/fash/-/fash-1.2.0.tgz","integrity":"sha512-A/uE7KuqeRim4TEJJCrAzwCrm49gUKFCJpOo8pT7lYwx5X0oQClvTS/B3WoWddoGaIMrC0RoVZLgI07bt4XoFg==","signatures":[{"sig":"MEUCIQDFxv6L6mRFduM+su/jzp32tkKS0MLuy2J2JCUjeVBLRQIgR52vrjSSWwjDhyqvFIS+4S6KMRWZzlv9gKb88aq+Y8U=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"cmdln":"1.1.1","bignum":"0.6.0","bunyan":"*","verror":"1.3.6","dashdash":"1.2.1","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","nodeunit":"0.8.0"}},"1.2.1":{"name":"fash","version":"1.2.1","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.2.1","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"e1845b0704737fb653874b9a9d966237cec756f9","tarball":"https://registry.npmjs.org/fash/-/fash-1.2.1.tgz","integrity":"sha512-Qib2XGCaPpAFS8srCE+VsPJYyJ7NoCx30LRa4SP29Bz0w//uDE3wkCp1TYXiAvC52Zk7njtducRvJj8B2BBFWg==","signatures":[{"sig":"MEQCIG9L5akKNu2sENnqKu0yIVO1XkxeWTxYuTSjlJihpV00AiBTmiThbDlyy5NLIRxmbSx33MsPOyx4jvRgUfL16FFhUw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"cmdln":"1.1.1","bignum":"0.6.0","bunyan":"*","verror":"1.3.6","dashdash":"1.2.1","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","nodeunit":"0.8.0"}},"1.2.2":{"name":"fash","version":"1.2.2","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.2.2","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"788918ab6c80ac873b7164c016b960ebbe454203","tarball":"https://registry.npmjs.org/fash/-/fash-1.2.2.tgz","integrity":"sha512-00cAqAJpQs3YL5V1YAZcaqIAHKOwonxAadVZaFn4pDrjnf+eYFjVGsNqdV3xuJdM2N8QOXH64w5O2Ht7EttXWQ==","signatures":[{"sig":"MEUCIQCw+3ZuOEurXnn1thKp4+TbR5YH4nPPPeIW8MPoel9m6QIgWpOnWKhXTWvBFdjNNjwvo6FTEouc5UIgMCDLwdJ2NF4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"cmdln":"1.1.1","bignum":"0.6.0","bunyan":"*","verror":"1.3.6","dashdash":"1.2.1","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","nodeunit":"0.8.0"}},"1.2.3":{"name":"fash","version":"1.2.3","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.2.3","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"ab051f5e8c352f9488481451b87da51d280c3ca4","tarball":"https://registry.npmjs.org/fash/-/fash-1.2.3.tgz","integrity":"sha512-Vh6tHfDSd4JO6LqBqauzBJKBABUz47JQR5692K8YhO16jRsDCjiud7UAItK57oG404iwV6rEImnhbGx8vB6jeg==","signatures":[{"sig":"MEQCIEsqUOS6iC63FhNtrpQJue2ycford2Pxj/33skGwOjymAiAm7FofbEShbv3b/sv4Okw7DcKbGoPI9p4WSOzoi0t1eg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"cmdln":"1.1.1","bignum":"0.6.0","bunyan":"*","verror":"1.3.6","dashdash":"1.2.1","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","nodeunit":"0.8.0"}},"1.2.4":{"name":"fash","version":"1.2.4","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@1.2.4","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"b32aa827f3d81258b92b7ffe69e9ca034c0b1316","tarball":"https://registry.npmjs.org/fash/-/fash-1.2.4.tgz","integrity":"sha512-3KAAyH79kW025RsRuiE4y97YEVaSs4QlPoiHfKMyCVQPHfMXv7vYk8zleffWQMRaay8VPxTjkl9KqqrArYGtbA==","signatures":[{"sig":"MEYCIQCcH+DLlUu+XC8Tk8SBLlE6hhbwoeqBZIavM+1pk8GwbgIhAPUBXIMZvT1XDThCGSWbp0eiTethDHiaGm0T1I+VcOfb","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.18","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"cmdln":"1.1.1","bignum":"0.6.0","bunyan":"*","verror":"1.3.6","dashdash":"1.2.1","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","nodeunit":"0.8.0"}},"2.0.0":{"name":"fash","version":"2.0.0","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.0.0","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"d5d214693f79c12c6b148ea8b0b2414e6fe53dd5","tarball":"https://registry.npmjs.org/fash/-/fash-2.0.0.tgz","integrity":"sha512-LwXee08ls2D6FUgMUt01yEpWf3qhu7vfKfVLIFvQb12dpeDTar4HJgvCnk8F6cAwjXni0ZW77LyGkVQvvJfgpA==","signatures":[{"sig":"MEUCIQDZvO78mtPBd91RTnCye6XLNLjDeIER1gPtGVhs94dFsQIgMcIM4FRO5s2+m2k40GMWe6Rn7BCYdvqPNBA/sPGzx8o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.30","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"once":"1.1.1","cmdln":"1.1.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","vasync":"1.3.3","verror":"1.3.6","levelup":"0.12.0","dashdash":"1.2.1","leveldown":"0.6.2","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","nodeunit":"0.8.1"}},"2.0.1":{"name":"fash","version":"2.0.1","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.0.1","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"}],"bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"593353775226959a351e2029f540b25257209f30","tarball":"https://registry.npmjs.org/fash/-/fash-2.0.1.tgz","integrity":"sha512-hUYYm07AcpjU7DXCJvglO5dY6bE3xFlG6eaWJbD3G8bZIhFnip1dD4W5qiX+TZ2chEDwNv9h+Lm83xTo2VsRoQ==","signatures":[{"sig":"MEUCIQDtIGHuhc92jC+8wx/R7S4WtxfLkw7iJhZVuK94/Di4uwIgXnbigiJoWW01N/0KYtZ6SmkcCdSEjty1GM/Ja9mpXgg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.30","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"once":"1.1.1","cmdln":"1.1.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","vasync":"1.3.3","verror":"1.3.6","levelup":"0.12.0","dashdash":"1.2.1","leveldown":"0.6.2","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","nodeunit":"0.8.1"}},"2.0.2":{"name":"fash","version":"2.0.2","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.0.2","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"}],"bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"f6ebf091ff1264e908758fef545cdaa20f3c33a7","tarball":"https://registry.npmjs.org/fash/-/fash-2.0.2.tgz","integrity":"sha512-cMuv08/WlbuDZctHI3Vejkvt/nQe2o9i9baytxwCRqC91sNWeAqPqbK7nRV8FtzH5Vh+BGf/Wd3u3ObCP9q9TQ==","signatures":[{"sig":"MEYCIQDYttMWft+XgYoCKRpq6ak+YOa0U98wf3ApvKFwV6ifFQIhANL3JP/8odCR21Q4lt2tvEA+WcabZMp2lhfHxFWQ2TsO","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.30","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"once":"1.1.1","cmdln":"1.1.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","vasync":"1.3.3","verror":"1.3.6","levelup":"0.12.0","dashdash":"1.2.1","leveldown":"0.6.2","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","nodeunit":"0.8.1","node-uuid":"1.4.1"}},"2.1.0":{"name":"fash","version":"2.1.0","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.1.0","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"}],"bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"7523900da84c443bea08ea02f0f55fac38afeb65","tarball":"https://registry.npmjs.org/fash/-/fash-2.1.0.tgz","integrity":"sha512-GRgfdzV8kCp+NEjnMQv8jglRvazFmahSOW+IUAbg/il2nOPObuy7yl8oa8Ax22mLxKxnJe2yb6fQWTNBEz7ZYA==","signatures":[{"sig":"MEYCIQC2Ek0rPBqMFIjI129Pz2falzNoZ2ISug0Jfaww9CdqzQIhAIRUvOSK9ZaU5gBFBfmrqusc72RFZrmKEhtgEPvyi/c8","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.30","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"once":"1.1.1","cmdln":"1.1.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","vasync":"1.3.3","verror":"1.3.6","levelup":"0.12.0","dashdash":"1.2.1","leveldown":"0.6.2","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","nodeunit":"0.8.1","node-uuid":"1.4.1"}},"2.1.1":{"name":"fash","version":"2.1.1","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.1.1","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"}],"bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"03f27dddafc87450fa1d95d467d6a581d5a7182e","tarball":"https://registry.npmjs.org/fash/-/fash-2.1.1.tgz","integrity":"sha512-kOXwLu010m8sMpPMIFGV9Qk5euqmzhpDscCkFRrVHz1H6WnwH0LmDxh72yZGazO6KnN7GftfvkkhjHQTks60AQ==","signatures":[{"sig":"MEQCIFderIzm93JKwOyMuT+drP44PmaSynHiXP7IFm7lJNtDAiANSseV610yp14hjexd0K3kDA/OMalo6P1Ne8PRINOWfg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.2.30","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"once":"1.1.1","cmdln":"1.1.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","vasync":"1.3.3","verror":"1.3.6","levelup":"0.12.0","dashdash":"1.2.1","leveldown":"0.6.2","assert-plus":"0.1.2"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","nodeunit":"0.8.1","node-uuid":"1.4.1"}},"2.2.0":{"name":"fash","version":"2.2.0","keywords":["consistent hashing","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.2.0","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"}],"bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"e72ab99ea9d921550dee1063d6b40812622fbf3f","tarball":"https://registry.npmjs.org/fash/-/fash-2.2.0.tgz","integrity":"sha512-KrvPlbAC70TrUQ+FmAs2847o7o2OcwOzRou6+0I5zjZO4UJSw7O+ce7B1D/5i2BW+A0tGNBI6ZDNHgd21dDVFg==","signatures":[{"sig":"MEQCICQerLIb6Or1Js0YoIhZYAKS2sTeL8eyi64+1CI5X9cGAiAZ5ipCNOkqI1FqYvHqQ9xhV+XsuZSwJBEUmVkAk1zUEg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.3.8","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"once":"1.1.1","cmdln":"1.1.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","vasync":"1.3.3","verror":"1.3.6","levelup":"git://github.com/yunong/node-levelup.git#c8d0bcb","dashdash":"1.2.1","leveldown":"0.8.0","assert-plus":"0.1.2","dtrace-provider":"0.2.8"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","nodeunit":"0.8.1","node-uuid":"1.4.1"}},"2.3.0":{"name":"fash","version":"2.3.0","keywords":["consistent hashing","consistent hash","hash","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.3.0","maintainers":[{"name":"isaacs","email":"i@izs.me"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"}],"homepage":"https://github.com/yunong/node-fash","bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"4d51fed89f9367fa5a35cd61c56e6b8853f689e2","tarball":"https://registry.npmjs.org/fash/-/fash-2.3.0.tgz","integrity":"sha512-55vVIMkLcsfcN/fABRFCoT+63i0MHRsRnNzenOt09W6kmcTl3pAsYN4RECUKGD3/bzdGRxCM7HCd/iBlm7YU2Q==","signatures":[{"sig":"MEUCIQDKZVLH+oNih+54mLwp4klI/M3eYXmuhZIKB5SL8agq6QIgciDrVz9O1O29fQdcU77m0pgGg3k/3FmacH3Ws4ZxIrk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"nodeunit test/*.test.js"},"_npmUser":{"name":"isaacs","email":"i@izs.me"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.3.24","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"once":"1.1.1","cmdln":"1.1.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","vasync":"1.3.3","verror":"1.3.6","levelup":"git://github.com/yunong/node-levelup.git#273cbda","dashdash":"1.2.1","leveldown":"0.8.0","assert-plus":"0.1.2","dtrace-provider":"0.2.8"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","restify":"2.6.0","nodeunit":"0.8.1","node-uuid":"1.4.1"},"optionalDependencies":{"dtrace-provider":"0.2.8"}},"2.3.1":{"name":"fash","version":"2.3.1","keywords":["consistent hashing","consistent hash","hash","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.3.1","maintainers":[{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"}],"homepage":"https://github.com/yunong/node-fash","bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"72d0b0e8039a0e5cc4f3896a051970aa5adc96e4","tarball":"https://registry.npmjs.org/fash/-/fash-2.3.1.tgz","integrity":"sha512-JjO2ysEZAJ+herMZY6UqSOd5Ox5afSxaizOLHxM2BJ74sbXv5P9Wslsdf1Ts4K2vFS2SyAN3FKtzra+tc8IrMA==","signatures":[{"sig":"MEUCIAKNLapZW0oskRwbDtKXDWlqDWhwcTZ80uRO/lqEsZXhAiEA8xAsFFzU8DDmT1voS11aJXNH7r+TI2ah/DM6TxnFpGc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","engines":{"node":">=0.8"},"scripts":{"test":"./node_modules/.bin/nodeunit test/*.test.js"},"_npmUser":{"name":"yunong","email":"yjxiao@gmail.com"},"repository":{"url":"https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"1.3.23","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"dependencies":{"once":"1.1.1","cmdln":"1.1.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","vasync":"1.3.3","verror":"1.3.6","levelup":"git://github.com/yunong/node-levelup.git#273cbda","dashdash":"1.2.1","leveldown":"0.8.0","assert-plus":"0.1.2","dtrace-provider":"0.2.8"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","restify":"2.6.0","nodeunit":"0.8.1","node-uuid":"1.4.1"},"optionalDependencies":{"dtrace-provider":"0.2.8"}},"2.4.0":{"name":"fash","version":"2.4.0","keywords":["consistent hashing","consistent hash","hash","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.4.0","maintainers":[{"name":"jclulow","email":"josh@sysmgr.org"},{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"}],"homepage":"https://github.com/yunong/node-fash#readme","bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"78dc7bacc21ea93292310c577f2cc023ac0956f5","tarball":"https://registry.npmjs.org/fash/-/fash-2.4.0.tgz","integrity":"sha512-wK9+HRopsUYvv5XGLeJok3Tyi4DxCvhoRc5ismTGS6YtF6lMs5WWrrxxzD0FQ2MZ30wcvuast+F98RxprORbXg==","signatures":[{"sig":"MEUCIQCjlDDO4HMYTXxUiYJa76AwC8w0pIiezR6xSw/LzXo1JgIgTUknXrb0cAqHe5RFUl2/I+KW21jS3GbjY3YQpjittvI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","config":{"leveldb_test_algorithm":"sha256"},"_shasum":"78dc7bacc21ea93292310c577f2cc023ac0956f5","engines":{"node":">=0.8"},"gitHead":"94931cccbb1960ad24d8a8a77e2a2e02e8d99207","scripts":{"test":"nodeunit test/*.test.js","pretest":"./lint.sh"},"_npmUser":{"name":"princesspretzel","email":"brittany.wald@joyent.com"},"repository":{"url":"git+https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"2.15.1","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"_nodeVersion":"0.10.48","dependencies":{"once":"1.1.1","cmdln":"1.3.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","jsprim":"1.4.0","vasync":"1.6.4","verror":"1.3.6","levelup":"git://github.com/yunong/node-levelup.git#273cbda","dashdash":"1.4.0","leveldown":"0.8.0","assert-plus":"0.1.2","dtrace-provider":"0.2.8"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","restify":"2.6.0","nodeunit":"git://github.com/yunong/nodeunit.git#master","node-uuid":"1.4.1"},"optionalDependencies":{"dtrace-provider":"0.2.8"},"_npmOperationalInternal":{"tmp":"tmp/fash-2.4.0.tgz_1503444922511_0.12069182633422315","host":"s3://npm-registry-packages"}},"2.4.1":{"name":"fash","version":"2.4.1","keywords":["consistent hashing","consistent hash","hash","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.4.1","maintainers":[{"name":"princesspretzel","email":"brittany.wald@joyent.com"},{"name":"jclulow","email":"josh@sysmgr.org"},{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"}],"homepage":"https://github.com/yunong/node-fash#readme","bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"9f8aaeca8fa6e7896e403711567daee7854b2a47","tarball":"https://registry.npmjs.org/fash/-/fash-2.4.1.tgz","integrity":"sha512-NZATqIyObffQpAdATlM3/Pw02k6i6MT8y+g/QzDIBoZgADADjlB7WpKULeHOPidaMKmt+3lzEeHC3eW9/Gg9GA==","signatures":[{"sig":"MEUCIADBWK91/6hCvf5TZoGHyiiSuaFwxBCYJZWZHI6kT7FYAiEAnPT4ti+VHvcZUM+ueVoiMcnogkVwzxeS+/zs1i4HFbU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","_shasum":"9f8aaeca8fa6e7896e403711567daee7854b2a47","engines":{"node":">=0.8"},"gitHead":"bb9d561ce6e19683aac147470e3a51067858bd47","scripts":{},"_npmUser":{"name":"princesspretzel","email":"brittany.wald@joyent.com"},"repository":{"url":"git+https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"2.15.1","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"_nodeVersion":"0.10.48","dependencies":{"once":"1.1.1","cmdln":"1.3.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","jsprim":"1.4.0","vasync":"1.6.4","verror":"1.3.6","levelup":"git://github.com/yunong/node-levelup.git#273cbda","dashdash":"1.4.0","leveldown":"0.8.0","assert-plus":"0.1.2","dtrace-provider":"0.2.8"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","restify":"2.6.0","nodeunit":"git://github.com/yunong/nodeunit.git#master","node-uuid":"1.4.1"},"optionalDependencies":{"dtrace-provider":"0.2.8"},"_npmOperationalInternal":{"tmp":"tmp/fash-2.4.1.tgz_1505932560367_0.48927231691777706","host":"s3://npm-registry-packages"}},"2.5.0":{"name":"fash","version":"2.5.0","keywords":["consistent hashing","consistent hash","hash","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@2.5.0","maintainers":[{"name":"princesspretzel","email":"brittany.wald@joyent.com"},{"name":"jclulow","email":"josh@sysmgr.org"},{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"},{"name":"Brittany Wald","email":"brittany.wald@joyent.com"}],"homepage":"https://github.com/yunong/node-fash#readme","bugs":{"url":"https://github.com/yunong/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"4d456819b5b73c0bea7da7e6dbb7f7d19fc8cf78","tarball":"https://registry.npmjs.org/fash/-/fash-2.5.0.tgz","integrity":"sha512-Up6JDcdi7iXbgujZ71BrWrhuUdjq9TcTJ06QRZhxsX8mARRzgCIgZxxQkVASSMVUe0l0ONJ4yIAoVMQ7NKNg2g==","signatures":[{"sig":"MEUCIEry7oRXOcwY5LOvnGnxyePgGMvtgHWcXdhJQf3410GHAiEAxkh5lOW6xD3PGZqkFiBt6Boc7evQuzPmnzujoHX2ef4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./lib/index.js","_from":".","_shasum":"4d456819b5b73c0bea7da7e6dbb7f7d19fc8cf78","engines":{"node":">=0.8"},"gitHead":"2076fc4830e5be66f3e4fd834c81ed6ff92bf844","scripts":{},"_npmUser":{"name":"princesspretzel","email":"brittany.wald@joyent.com"},"repository":{"url":"git+https://github.com/yunong/node-fash.git","type":"git"},"_npmVersion":"2.15.1","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"_nodeVersion":"0.10.48","dependencies":{"once":"1.1.1","cmdln":"1.3.1","redis":"0.8.4","bignum":"0.6.0","bunyan":"*","jsprim":"1.4.0","vasync":"1.6.4","verror":"1.3.6","levelup":"git://github.com/yunong/node-levelup.git#273cbda","dashdash":"1.4.0","leveldown":"0.8.0","assert-plus":"0.1.2","dtrace-provider":"0.2.8"},"devDependencies":{"bunyan":"*","lodash":"1.3.1","restify":"2.6.0","nodeunit":"git://github.com/yunong/nodeunit.git#master","node-uuid":"1.4.1"},"optionalDependencies":{"dtrace-provider":"0.2.8"},"_npmOperationalInternal":{"tmp":"tmp/fash-2.5.0.tgz_1506098174698_0.16992619610391557","host":"s3://npm-registry-packages"}},"3.0.0":{"name":"fash","version":"3.0.0","keywords":["consistent hashing","consistent hash","hash","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@3.0.0","maintainers":[{"name":"bahamas10","email":"dave@daveeddy.com"},{"name":"bahamat","email":"bahamat@digitalelf.net"},{"name":"chudley","email":"aguycalledrichard@gmail.com"},{"name":"jclulow","email":"josh@sysmgr.org"},{"name":"kkantor","email":"kody.kantor@joyent.com"},{"name":"kusor","email":"kusorbox@gmail.com"},{"name":"michael.hicks","email":"michael.hicks@joyent.com"},{"name":"todd.whiteman","email":"todd.whiteman@joyent.com"},{"name":"trentm","email":"trentm@gmail.com"},{"name":"wyatt","email":"wpreul@gmail.com"},{"name":"yunong","email":"yjxiao@gmail.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"},{"name":"Brittany Wald","email":"brittany.wald@joyent.com"}],"homepage":"https://github.com/joyent/node-fash#readme","bugs":{"url":"https://github.com/joyent/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"b01ded7fc7c0645eeba4593bcf424bfc67edae34","tarball":"https://registry.npmjs.org/fash/-/fash-3.0.0.tgz","fileCount":8,"integrity":"sha512-hQZIncdfYPF6v/ahhq4/LlthrjVnjk2dCxBmQHUJsAwC+ExLym+RLhjGEUrXs0jsJLhMubpCKnprnf0XtUXQfQ==","signatures":[{"sig":"MEUCIHuChVzsjX5WM/X+UQ/ruSiO7ROOdXL6+hGsPu+sfiEyAiEAlUUzFKgzE37MaRXXZKv+OgLbCHKVUFQ3jtO9pdiLG2Y=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":160449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd3Yj/CRA9TVsSAnZWagAAWIQQAJPE4q0k0LT/byYJbref\nPs1AM2XSQOHIOl7ZLbyG5WqAKL/amkxEsU/1lUzqtjkQEYRE55weiQwglXRL\nnDNU2go6N7un433THUXLfXF2pb4yPrFayOeZM1xEsvoOgNKsFLvRvUHuNScD\nJVyzlJxNAnBVlDWPs8/amoXPofOazWAvsMRKkFeFahWCxD28COMgdDC3Yupz\nI4rGSZ3oKKk+dL2olKYqgadPDeHybSGBV+8KLRjUWG3+RDY5sh/aSeKCN1BS\n9yoFUHsJqo3s0khsVIyjWb2NR/8zugGAIoGc1pPBO83ERYI/J87L9hEPUeTB\n4OqH2g0kM6VavOomtwLD19yindZb6bOugDHIJNLUalB1gxL7GAJgTQYHF0rz\neubQunowu5zfRcXDcOhwK1lb0X8ett87eMrBrubyeALXZ6TCbo28VmxHX5k/\niZvnsqGJRNKtkcCFLJrcOe1qUBU9Byb/u9H7ZLbI9pfz+NMAmczUuDBpUJZ+\nHg+kOtiM7QQMYqi29w8gb4v6BUeP3AvOTWnwIm4ad9+N2n/c7Sz/+RQkpJbA\n8fLq+ICYgHLAgIsvO/Kmph++AkUphTTTluMGr8WeG0v2BliY9qEi9o3yFaCX\nmGfLHiNPUcD0eP5CZupw71hNriD0W8iMbmY9t4mWQEQGhwcQHDJ9WyrfthK+\n1YiM\r\n=IUq2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./lib/index.js","engines":{"node":">=0.10"},"gitHead":"0bb301ff41b0446deb1e2c49f8efdf9666cc8618","_npmUser":{"name":"bahamas10","email":"dave@daveeddy.com"},"repository":{"url":"git+https://github.com/joyent/node-fash.git","type":"git"},"_npmVersion":"6.11.3","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"_nodeVersion":"12.11.1","dependencies":{"once":"1.1.1","cmdln":"1.3.1","level":"4.0.0","redis":"0.8.4","bignum":"0.13.0","bunyan":"1.8.10","jsprim":"1.4.0","vasync":"1.6.4","verror":"1.3.6","dashdash":"1.4.0","assert-plus":"1.0.0","dtrace-provider":"0.8.8"},"_hasShrinkwrap":false,"devDependencies":{"uuid":"3.3.3","lodash":"1.3.1","nodeunit":"0.8.2"},"optionalDependencies":{"dtrace-provider":"0.8.8"},"_npmOperationalInternal":{"tmp":"tmp/fash_3.0.0_1574799614739_0.4938453388797266","host":"s3://npm-registry-packages"}},"3.0.1":{"name":"fash","version":"3.0.1","keywords":["consistent hashing","consistent hash","hash","hashing","distributed","dynamo","hash ring"],"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"_id":"fash@3.0.1","maintainers":[{"name":"bahamat","email":"bahamat@digitalelf.net"},{"name":"todd.whiteman","email":"todd.whiteman@joyent.com"},{"name":"kusor","email":"kusorbox@gmail.com"},{"name":"michael.hicks","email":"michael.hicks@joyent.com"},{"name":"trentm","email":"trentm@gmail.com"},{"name":"jclulow","email":"josh@sysmgr.org"},{"name":"wyatt","email":"wpreul@gmail.com"},{"name":"bahamas10","email":"dave@daveeddy.com"},{"name":"kkantor","email":"kody.kantor@joyent.com"},{"name":"chudley","email":"aguycalledrichard@gmail.com"},{"name":"isaacdavis","email":"isaac.davis@joyent.com"}],"contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"},{"name":"Brittany Wald","email":"brittany.wald@joyent.com"},{"name":"Brian Bennett","email":"brian.bennett@mnx.io"}],"homepage":"https://github.com/TritonDataCenter/node-fash#readme","bugs":{"url":"https://github.com/TritonDataCenter/node-fash/issues"},"bin":{"fash":"bin/fash.js"},"dist":{"shasum":"7b2185e6cf138a0de51b66ec4e6b396f137a5d10","tarball":"https://registry.npmjs.org/fash/-/fash-3.0.1.tgz","fileCount":8,"integrity":"sha512-Pssi62/vKGK7CI/8qtecUBw1eZJoEcXp8TrZ+dvEkzWjqzxkPzMhUgNkB85AQQGbJcJy0W/+QEi7IR0R7gTdGg==","signatures":[{"sig":"MEUCIQCMLdXN24W5Xj3yKQ350SbliH6XVnRQXKgKcCW9IyLhkQIgKJ5/2R890SqGE1NLEnSsrCToW8F2xLGYXogqmwv3fW8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":160541},"main":"./lib/index.js","engines":{"node":">=0.10"},"gitHead":"ed821d2e945a92d9e9b574ac92baacc0aafdc961","_npmUser":{"name":"bahamat","email":"bahamat@digitalelf.net"},"repository":{"url":"git+https://github.com/TritonDataCenter/node-fash.git","type":"git"},"_npmVersion":"9.5.1","description":"A consistent hashing library for node","directories":{"lib":"./lib"},"_nodeVersion":"18.16.0","dependencies":{"once":"1.1.1","cmdln":"1.3.1","level":"4.0.0","redis":"0.8.4","bignum":"0.13.1","bunyan":"1.8.10","jsprim":"1.4.2","vasync":"1.6.4","verror":"1.3.6","dashdash":"1.4.0","assert-plus":"1.0.0","dtrace-provider":"0.8.8"},"_hasShrinkwrap":false,"devDependencies":{"uuid":"3.3.3","lodash":"1.3.1","nodeunit":"0.9.5"},"optionalDependencies":{"dtrace-provider":"0.8.8"},"_npmOperationalInternal":{"tmp":"tmp/fash_3.0.1_1685041566775_0.7613256232258121","host":"s3://npm-registry-packages"}}},"time":{"created":"2012-07-24T21:54:20.722Z","modified":"2025-11-26T18:15:41.897Z","0.1.0":"2012-07-24T21:54:22.327Z","0.1.1":"2012-08-06T16:54:10.124Z","1.0.0":"2013-04-01T20:59:17.217Z","1.1.0":"2013-05-06T20:54:03.828Z","1.1.1":"2013-05-07T22:33:30.762Z","1.1.2":"2013-05-07T23:59:40.616Z","1.1.3":"2013-05-08T23:09:35.325Z","1.1.4":"2013-05-13T01:17:15.632Z","1.1.5":"2013-05-13T17:54:15.314Z","1.2.0":"2013-05-20T20:47:44.122Z","1.2.1":"2013-05-21T23:39:06.262Z","1.2.2":"2013-06-04T21:17:00.174Z","1.2.3":"2013-06-11T22:24:03.312Z","1.2.4":"2013-06-12T22:26:56.903Z","2.0.0":"2013-08-20T17:59:38.396Z","2.0.1":"2013-08-22T23:06:08.619Z","2.0.2":"2013-08-26T23:10:26.371Z","2.1.0":"2013-09-04T21:13:56.314Z","2.1.1":"2013-09-05T20:38:53.496Z","2.2.0":"2013-09-25T22:47:38.863Z","2.3.0":"2014-01-14T23:18:15.203Z","2.3.1":"2014-03-12T23:50:53.189Z","2.4.0":"2017-08-22T23:35:22.598Z","2.4.1":"2017-09-20T18:36:00.458Z","2.5.0":"2017-09-22T16:36:14.769Z","3.0.0":"2019-11-26T20:20:14.951Z","3.0.1":"2023-05-25T19:06:06.948Z"},"bugs":{"url":"https://github.com/TritonDataCenter/node-fash/issues"},"author":{"name":"Yunong J Xiao","email":"yjxiao@gmail.com"},"homepage":"https://github.com/TritonDataCenter/node-fash#readme","keywords":["consistent hashing","consistent hash","hash","hashing","distributed","dynamo","hash ring"],"repository":{"url":"git+https://github.com/TritonDataCenter/node-fash.git","type":"git"},"description":"A consistent hashing library for node","contributors":[{"name":"Mark Cavage","email":"mcavage@gmail.com"},{"name":"Fred Kuo","email":"deepevil@gmail.com"},{"name":"Brittany Wald","email":"brittany.wald@joyent.com"},{"name":"Brian Bennett","email":"brian.bennett@mnx.io"}],"maintainers":[{"email":"todd.whiteman@joyent.com","name":"todd.whiteman"},{"email":"kusorbox@gmail.com","name":"kusor"},{"email":"michael.hicks@joyent.com","name":"michael.hicks"},{"email":"bahamat@digitalelf.net","name":"bahamat"},{"email":"Tr@visPaul.me","name":"tpaul"},{"email":"danmcd@edgecast.io","name":"kebesays"},{"email":"trentm@gmail.com","name":"trentm"},{"email":"josh@sysmgr.org","name":"jclulow"},{"email":"wpreul@gmail.com","name":"wyatt"},{"email":"dave@daveeddy.com","name":"bahamas10"},{"email":"kody.kantor@joyent.com","name":"kkantor"},{"email":"aguycalledrichard@gmail.com","name":"chudley"},{"email":"isaac.davis@joyent.com","name":"isaacdavis"}],"readme":"# fash: consistent hashing library for node.js\n\n[![NPM](https://nodei.co/npm/fash.png)](https://nodei.co/npm/fash/)\n[![NPM](https://nodei.co/npm-dl/fash.png)](https://nodei.co/npm/fash/)\n\n\nThis module provides a consistent hashing library. Notably, this module has the\nability to **deterministically generate the same hash ring topology across a\nset of distributed hosts**. Fash also handles collisions of nodes on the ring\nand ensures no two nodes will share the same spot on the ring. Additionally,\nfash provides the ability to add, remove, or remap physical nodes on the ring\n-- useful when a particular physical node has hit its scaling bottleneck.\n\n<a name=\"index\"></a>\n# Index\n\n* [Design Summary](#design-summary)\n* [Examples for Consumers](#examples-for-consumers)\n    - [Bootstrapping a New Hash Ring](#bootstrapping-a-new-hash-ring)\n    - [Adding More Pnodes to the Ring](#adding-more-pnodes-to-the-ring)\n    - [Adding Optional Data to a Virtual Node](#adding-optional-data-to-a-virtual-node)\n* [Development Information](#development-information)\n    - [Command Line Ring Creation](#command-line-ring-creation)\n        * [Backends: an interlude](#backends-an-interlude)\n    - [Walkthrough: working with the hash ring](#walkthrough-working-with-the-hash-ring)\n        * [Adding Data to Vnodes](#adding-data-to-vnodes)\n        * [Remapping Vnodes](#remapping-vnodes)\n        * [Removing Pnodes](#removing-pnodes)\n    - [LevelDB schema](#leveldb-schema)\n    - [LevelDB-supported CLI](#leveldb-supported-cli)\n    - [Running Tests](#running-tests)\n\n# Design Summary\n\nFash consists of a mapping of a set of fixed virtual nodes (vnodes) -- usually\na large number, say 1000000 -- distributed across the hash ring. It is then\npossible to map these virtual nodes to a set of physical nodes (pnodes).  In\npractice, pnodes are usually physical shards or servers in a distributed\nsystem. This gives the flexibility of mutating the hashspace of pnodes and the\nnumber of pnodes by re-mapping the vnode assignments.  For a more in-depth\nexplanation, see the [Development Information](#development-information) section.\n\n# Examples for Consumers\n\nExamples can be found in the unit tests. Here are a few.\n\n## Bootstrapping a New Hash Ring\n\n    var fash = require('fash');\n    var Logger = require('bunyan');\n\n    var LOG = new Logger({\n        name: 'fash',\n        level: 'info'\n    });\n\n    var chash = fash.create({\n        log: LOG, // optional [bunyan](https://github.com/trentm/node-bunyan) log object.\n        algorithm: 'sha-256', // Can be any algorithm supported by openssl.\n        pnodes: ['A', 'B', 'C', 'D', 'E'], // The set of physical nodes to insert into the ring.\n        vnodes: 1000000 // The virtual nodes to place onto the ring. Once set, this can't be changed for the lifetime of the ring.\n        backend: fash.BACKEND.IN_MEMORY\n    });\n\n    var node = chash.getNode('someKeyToHash');\n    console.log('key hashes to pnode', node);\n\nIf the config used to bootstrap fash is the same across all clients, then the\nring toplogy will be the same as well. By default, fash will evenly distribute\nvnodes across the set of pnodes. If you wish to have a custom mapping of pnodes\nto vnodes, see the later section on serialization.\n\n## Remapping Vnodes in the Ring\nFash gives you the ability to add and rebalance the vnodes in the ring by using\nthe remapVnode() function, which returns an optional callback.\n\nYou can also remove pnodes from the ring, but **you must first rebalance the\nring by reassigning its vnodes to other pnodes** via remapVnode(). Then you can\ninvoke removePnode(), which will return an optional callback.\n\nYou can assign an arbitrary number of vnodes to the new pnode -- also -- the\npnode can be a new node, or an existing one.  Again, as long as the order of\nremoves and remaps is consistent across all clients, the ring toplogy will be\nconsistent as well.\n\n    var fash = require('fash');\n    var Logger = require('bunyan');\n\n    var LOG = new Logger({\n        name: 'fash',\n        level: 'info'\n    });\n\n    var chash = fash.create({\n        log: LOG,\n        algorithm: 'sha256',\n        pnodes: ['A', 'B', 'C', 'D', 'E'],\n        backend: fash.BACKEND.IN_MEMORY,\n        vnodes: 100000\n    });\n\n    // get vnodes from A\n    var aVnodes = chash.getVnodes('A');\n    aVnodes = aVnodes.slice(aVnodes.length / 2);\n\n    // remap some of A's vnodes to B\n    chash.remapVnode('B', aVnodes, function(ring, pnodes) {\n        console.log('new ring topology', ring);\n        console.log('changed pnode->vnode mappings', pnodes);\n    });\n\n## Adding More Pnodes to the Ring\n\nYou can add additional pnodes to the ring after fash has been initialized by\ninvoking remapVnode(), which optionally returns a callback. Note that adding\nthe callback will cause fash to create a new copy of the ring topology across\neach invocation -- do not do this if you have millions of vnodes, as this is\nquite slow and may consume all available memory, bringing the operation to a\nstandstill and locking up other resources.\n\n    var fash = require('fash');\n    var Logger = require('bunyan');\n\n    var LOG = new Logger({\n        name: 'fash',\n        level: 'info'\n    });\n\n    var chash = fash.create({\n        log: LOG,\n        algorithm: 'sha256',\n        pnodes: ['A', 'B', 'C', 'D', 'E'],\n        backend: fash.BACKEND.IN_MEMORY,\n        vnodes: 100000\n    });\n    // specify the set of virtual nodes to assign to the new physical node.\n    var vnodes = [0, 1, 2, 3, 4];\n\n    // add the physical node 'F' to the ring.\n    chash.remapVnode('F', vnodes, function(ring, changedNodes) {\n        console.log('ring topology updated', ring);\n        console.log('removed mappings', changedNodes);\n    });\n\nFash will remove the vnodes from their previously mapped physical nodes, and\nmap them to the new pnode.\n\n## Removing Pnodes from the Ring\nYou can remove physical nodes from the ring by first remapping the pnode's\nvnodes to another pnode, and then removing the pnode.\n\n    var fash = require('fash');\n    var Logger = require('bunyan');\n\n    var LOG = new Logger({\n      name: 'fash',\n      level: 'info'\n    });\n\n    var chash = fash.create({\n        log: LOG,\n        algorithm: 'sha256',\n        pnodes: ['A', 'B', 'C', 'D', 'E'],\n        backend: fash.BACKEND.IN_MEMORY,\n        vnodes: 10000\n    });\n\n    // get the vnodes that map to B\n    var vnodes = chash.getVnodes('B');\n    // rebalance them to A\n    chash.remapVnode('A', vnodes, function(ring, removedMap) {\n        // remove B\n        chash.removePnode('B', function(ring, pnode) {\n            if (!err) {\n                console.log('removed pnode %s', pnode);\n            }\n        });\n    });\n\n## Adding Optional Data to a Virtual Node\n\nSometimes, it might be helpful to associate state with a set of vnodes. An\nexample of this would be during routine system maintenance, an administrator\nmay want to set a certain set of vnodes to read only, and then set them back to\nwrite mode after the maintenance has completed.\n\nFash gives enables you to add arbitrary objects to vnodes by invoking the\n`addData` function.\n\n    chash.addData(10, 'foo');\n\nSubsequence `chash.getNode()` invocations which map to vnode 10 will return:\n\n    {\n        pnode: 'A',\n        vnode: 10,\n        data: 'foo'\n    }\n\nThe data associated with a virtual node is persistent across serializations and\nremaps.\n\n## Serializing and Persisting the Ring Toplogy\nAt any time, the ring toplogy can be accessed by:\n\n    chash.serialize();\n\nWhich returns the ring topology, which is a JSON serialized object string which\nlooks like\n\n    {\n        pnodeToVnodeMap: {\n            A: {0, 1, 2},\n            ...\n        }, // the pnode to vnode mapings.\n        vnode // the total number of vnodes in the ring.\n    }\n\nAdditionally, anytime remapVnode() is invoked, it can return a cb which\ncontains an updated version of this object that is **not** JSON serialized.\nFash can be instantiated given a topology object instead of a list of nodes.\nThis also allows you to specify a custom pnode to vnode topology -- as\nmentioned in the earlier bootstrapping section.\n\n    var fash = require('fash');\n    var Logger = require('bunyan');\n\n    var LOG = new Logger({\n        name: 'fash',\n        level: 'info'\n    });\n\n    var chash = fash.create({\n       log: LOG,\n       algorithm: 'sha256',\n       pnodes: ['A', 'B', 'C', 'D', 'E'],\n       backend: fash.BACKEND.IN_MEMORY,\n       vnodes: 10000\n    });\n\n    var topology = chash.serialize();\n\n    var chash2 = fash.deserialize({\n        log: LOG,\n        topology: topology\n    });\n\nThat's it, chash and chash2 now contain the same ring toplogy.\n\n# Development Information\n\nThe following information is intended to serve developers making changes or\nenhancements to this repository.  The command-line interface provides insight\ninto the structure of the hash ring topology at a deeper level than is made\navailable by the functions exposed for consumers of the node program.  Though\n`help` can be a good reference once the data structure is understood, this\ndocumentation seeks to give an overview of this structure more comprehensively\nthan makes sense to include in the tool itself.\n\nThe \"data structure\" is, at a high level, a mapping of pnodes or \"physical\nnodes\" to vnodes or \"virtual nodes.\"  It is intended to provide database-level\nassociations for an operator's (your) key-value store.  The advantage of this\nsetup is the flexibility to move vnodes between pnodes, while the association\nbetween the key-value pairings (where the \"key\" is hashed to an integer value\nand the \"value\" is a piece of plaintext data) and their assigned vnode is\npreserved.  This gives users the ability to retain relative groupings of keys\n(such as entries in the same file directory) that you've stored even in the\nevent that you need to move data around.  For example, if the data set grows\nlarge enough that additional pnodes are necessary to contain it all, this would\nnecessitate re-assignment of key-value pairings as some are moved to the new\npnode.  The level of abstraction the vnodes enable makes it possible to keep\ndifferent key-value pairings associated with one another in a granular and\nsimple way.\n\n## Command Line Ring Creation\n\nHere is the creation of a LevelDB-backed (meaning the key-value store is\nrepresented by the specs of LevelDB -- more information on that can be found [here](#leveldb-schema).\nThis is a hash ring for distributing 6 vnodes throughout 2 pnodes using the\ndefault hashing algorithm, sha256, which will be stored at the location `/var/tmp/rings/readme_sample`.\n\n    $ ./bin/fash.js create -l /var/tmp/rings/readme_sample -v 6 -a sha256 -p \"tcp://1.moray.emy-11.joyent.us:2020, tcp://2.moray.emy-11.joyent.us:2020\" -b leveldb\n\nHere is a <a name=\"diagram\">diagram</a> of what that ring would then look like:\n\n```\n                   PNODES                                       VNODES\n\n                                                             +-----------+\n+-------------------------------------------+   +--------+   |  \"0\": 1   |\n|                                           |                +-----------+\n|                                           |\n|   \"tcp://1.moray.emy-11.joyent.us:2020\"   |                +-----------+\n|                                           |   +--------+   |  \"2\": 1   |\n|                                           |                +-----------+\n|                                           |\n+-------------------------------------------+                +-----------+\n                                                +--------+   |  \"4\": 1   |\n                                                             +-----------+\n\n                                                             +-----------+\n+-------------------------------------------+   +--------+   |  \"1\": 1   |\n|                                           |                +-----------+\n|                                           |\n|   \"tcp://2.moray.emy-11.joyent.us:2020\"   |                +-----------+\n|                                           |   +--------+   |  \"3\": 1   |\n|                                           |                +-----------+\n|                                           |\n+-------------------------------------------+                +-----------+\n                                                +--------+   |  \"5\": 1   |\n                                                             +-----------+\n```\n\nThere is another way to create a ring topology if you already have a JSON file\nrepresentation of one.  If you want to manufacture one, you can use the [`print-hash`](#print-hash)\ncommand to print a JSON representation of a ring after creating it from scratch\n(as above).  Copying that into a `.json` file will give you the raw materials\nfor testing out the [`deserialize-ring`](#deserialize) method of ring creation\nbelow.\n\n<a name=\"sample-deserialize\"></a>\nThis is what the `.json` file should look like:\n\n    $ cat readme_sample.json\n    {\"vnodes\":6,\"pnodeToVnodeMap\":{\"tcp://1.moray.emy-11.joyent.us:2020\":{\"0\":1,\"2\":1,\"4\":1},\"tcp://2.moray.emy-11.joyent.us:2020\":{\"1\":1,\"3\":1,\"5\":1}},\"algorithm\":{\"NAME\":\"sha256\",\"MAX\":\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\",\"VNODE_HASH_INTERVAL\":\"2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"2.1.0\"}\n\nAnd then to actually generate and store that LevelDB-backed ring:\n\n    $ ./bin/fash.js deserialize-ring -l /var/tmp/rings/readme_sample_deserialized -f /var/tmp/rings/readme_sample.json\n\nTo see that the deserialized ring is the same as the original, the new ring can\nbe viewed with the same `print-hash` command used to show the original.\n<a name=\"sample-print\"></a>\n\n    $ ./bin/fash.js print-hash -l /var/tmp/rings/readme_sample_deserialized -b leveldb\n    {\"vnodes\":6,\"pnodeToVnodeMap\":{\"tcp://1.moray.emy-11.joyent.us:2020\":{\"0\":1,\"2\":1,\"4\":1},\"tcp://2.moray.emy-11.joyent.us:2020\":{\"1\":1,\"3\":1,\"5\":1}},\"algorithm\":{\"NAME\":\"sha256\",\"MAX\":\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\",\"VNODE_HASH_INTERVAL\":\"2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"2.1.0\"}\n\nThe fash tool can also do a direct comparison on its own with `diff`:\n<a name=\"sample-diff\"></a>\n\n    $ ./bin/fash.js diff -b leveldb /var/tmp/rings/readme_sample /var/tmp/rings/readme_sample_deserialized\n    {\"tcp://1.moray.emy-11.joyent.us:2020\":{\"removed\":[0],\"added\":[0]},\"tcp://2.moray.emy-11.joyent.us:2020\":{\"removed\":[1],\"added\":[1]}}\n\n### Backends: an interlude\n\nPlease note that for commands added before version 2.4.0 (of which `create` is\none), `-b` option has to be specified.  This command's purpose is to indicate\nwhether the topology is backed by a LevelDB or in-memory data store.\n\nAs of version 2, fash supported a LevelDB backend in addition to its original\nin-memory backend. The LevelDB backend has several advantages over the\nin-memory backend.  Notably, performance at scale should be faster since the\nring is no longer in v8.  Also the ring can be persisted on disk via LevelDB,\nremoving the need to load the ring into memory when the process is restarted.\n\nFor these reasons, at the time of writing, the **in-memory option** for\ncreating hash rings **is considered deprecated**, and may be removed in the\nfuture, once any existing dependencies on it can be verified and mitigated.\nThat is why this section focuses on working with the LevelDB-backed hash ring\nfunctionality, though it would be remiss not to explain why some commands will\nnot work without passing in `-b leveldb`.\n\nThe way to create a ring -- specifying a backend -- from the command line is\n[demonstrated above](#command-line-ring-creation).  Choosing a backend as a\nconsumer is done during fash initialization via the `backend` field.\n\n```javascript\n\n    var fash = require('fash');\n    var Logger = require('bunyan');\n\n    var LOG = new Logger({\n        name: 'fash',\n        level: 'info'\n    });\n\n    fash.create({\n        log: LOG, // optional [bunyan](https://github.com/trentm/node-bunyan) log object.\n        algorithm: 'sha-256', // Can be any algorithm supported by openssl.\n        pnodes: ['A', 'B', 'C', 'D', 'E'], // The set of physical nodes to insert into the ring.\n        vnodes: 1000000 // The virtual nodes to place onto the ring. Once set, this can't be changed for the lifetime of the ring.\n        backend: fash.BACKEND.LEVEL_DB,\n        location: '/tmp/chash'\n    }, function(err, chash) {\n        console.log('chash created');\n    });\n```\n\n## Walkthrough: working with the hash ring\n\nGetting back to the [example topology created above](#diagram); in order to\nunderstand how this is related to both the LevelDB key-value store and also\nthe pnode-vnode mapping, we will take just one \"vnode\" and break down the\ninformation inside it.\n\n                        +-----------+\n                        | \"4\": 1    |\n                        +-----------+\n\nThe `4` is the vnode number.  It is also the post-hash key in the sense of the\nkey-value LevelDB store.  What this mean is that if you have the key\n`/yunong/yunong.txt`, and then hash it using one of the available algorithms --\nsay, sha256 -- you will get back, in this ring topology, the value `4`.  So\nvnode `4` is where any data (value) you wanted to associate with the `/yunong/yunong.txt`\nkey will be stored.  In this case, we are storing the default value of 1 in\nthat vnode, associated with the key `/yunong/yunong.txt`.  To help illustrate\nthis point, there is a `get-node` command to show operators what any key is\nassociated with in terms of its data, pnode, and vnode mapping.\n<a name=\"sample-node\"></a>\n\n    $ ./bin/fash.js get-node \"/yunong/yunong.txt\" -l /var/tmp/rings/readme_sample -b leveldb\n    { pnode: 'tcp://1.moray.emy-11.joyent.us:2020',\n      vnode: 4,\n      data: 1 }\n\nThis operation is idempotent *as long as the topology does not change*. So `/yunong/yunong.txt`\nwill always map to vnode `4` UNLESS the number of pnodes or vnodes changes.\nFor this reason, remapping vnodes must *always be a manual process* -- we\ncannot recreate the ring with more pnodes or vnodes and expect that `/yunong/yunong.txt`\nwill still map to vnode `4` on the `tcp://1.moray.emy-11.joyent.us:2020` pnode.\n\n### Adding Data to Vnodes\n\nSo in an example where we are approaching full capacity on our two pnodes and\nneed to add a third, it might make sense to mark the vnodes we're going to move\nin some way.  Then our application can check for that demarcation and, say, not\naccept writes that might be lost during a move.  If the chosen identifer was `ro`\n(for READ ONLY), we could assign the value `ro` to the vnodes with the keys\nwe're shifting over.  This is done with the [`add-data`](#add-data) command:\n\n    $ ./bin/fash.js add-data -v 4 -d 'ro' -l /var/tmp/rings/readme_sample -b leveldb -o\n    {\"4\":\"ro\"}\n    {\"vnodes\":6,\"pnodeToVnodeMap\":{\"tcp://1.moray.emy-11.joyent.us:2020\":{\"0\":1,\"2\":1,\"4\":\"ro\"},\"tcp://2.moray.emy-11.joyent.us:2020\":{\"1\":1,\"3\":1,\"5\":1}},\"algorithm\":{\"NAME\":\"sha256\",\"MAX\":\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\",\"VNODE_HASH_INTERVAL\":\"2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"2.1.0\"}\n\nTo achieve this:\n\n                        +-----------+\n                        | \"4\": \"ro\" |\n                        +-----------+\n\nSo now vnode `4`, to which the key `/yunong/yunong.txt` maps, contains the\nvalue `ro`.\n\n### Remapping Vnodes\n\nNow that the vnode we want to move can be identified, we will want to actually\nmove it to the new pnode.  To see a full list of vnodes you have marked use\nthe command [`get-data-vnodes`](#get-data-vnodes).\n<a name=\"sample-datav\"></a>\n\n    $ ./bin/fash.js get-data-vnodes -l /var/tmp/rings/readme_sample\n    vnodeArray:  [ 4 ]\n\nIf this array were much larger, say, hundreds or thousands of vnodes, but you\nwere still just interested in knowing what data vnode `4` contained (or if at\nany point you needed to know which pnode it was assigned to) the [`get-vnode-pnode-and-data`](#get-vnode-pnode-and-data)\ncommand displays all available information about a given vnode.\n<a name=\"sample-datapv\"></a>\n\n    $ ./bin/fash.js get-vnode-pnode-and-data -v 4 -l /var/tmp/rings/readme_sample\n    vnodes:  { '4': { pnode: 'tcp://1.moray.emy-11.joyent.us:2020', vnodeData: 1 } }\n\nIn our example, from this you could conclude that vnode 4 was marked as\nread-only for relocation, so it is intended to be remapped to a new pnode `tcp://3.moray.emy-11.joyent.us:2020`\nwith [`remap-vnode`](#remap-vnode):\n\n    $ ./bin/fash.js remap-vnode -v 4 -b leveldb -p \"tcp://3.moray.emy-11.joyent.us:2020\" -l /var/tmp/rings/readme_sample -o\n    {\"tcp://3.moray.emy-11.joyent.us:2020\":\"4\"}\n    {\"vnodes\":6,\"pnodeToVnodeMap\":{\"tcp://1.moray.emy-11.joyent.us:2020\":{\"0\":1,\"2\":1},\"tcp://2.moray.emy-11.joyent.us:2020\":{\"1\":1,\"3\":1,\"5\":1},\"tcp://3.moray.emy-11.joyent.us:2020\":{\"4\":\"ro\"}},\"algorithm\":{\"NAME\":\"sha256\",\"MAX\":\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\",\"VNODE_HASH_INTERVAL\":\"2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"2.1.0\"}\n\nSo that the topology now looks like this:\n\n```\n                   PNODES                                       VNODES\n\n                                                             +-----------+\n+-------------------------------------------+   +--------+   |  \"0\": 1   |\n|                                           |                +-----------+\n|                                           |\n|   \"tcp://1.moray.emy-11.joyent.us:2020\"   |                +-----------+\n|                                           |   +--------+   |  \"2\": 1   |\n|                                           |                +-----------+\n|                                           |\n+-------------------------------------------+\n\n\n                                                             +-----------+\n+-------------------------------------------+   +--------+   |  \"1\": 1   |\n|                                           |                +-----------+\n|                                           |\n|   \"tcp://2.moray.emy-11.joyent.us:2020\"   |                +-----------+\n|                                           |   +--------+   |  \"3\": 1   |\n|                                           |                +-----------+\n|                                           |\n+-------------------------------------------+                +-----------+\n                                                +--------+   |  \"5\": 1   |\n                                                             +-----------+\n\n+-------------------------------------------+\n|                                           |\n|                                           |\n|   \"tcp://3.moray.emy-11.joyent.us:2020\"   |                +-----------+\n|                                           |   +--------+   | \"4\": \"ro\" |\n|                                           |                +-----------+\n|                                           |\n+-------------------------------------------+\n```\n\nThis command will also take a comma-separated list of vnodes (rather than just\na single one) to move a group of vnodes to the same pnode in one batch.  It is\nalso possible to remap vnodes to an existing pnode, rather than a new one.\n\n### Removing Pnodes\n\nIf you've decided that you no longer need a particular pnode, you can remove\nit.  There is one caveat, which is that you have to remap the vnodes it\ncontains first.  A list of vnodes on any pnode is available with [`get-vnodes`](#get-vnodes).\n<a name=\"sample-vnodes\"></a>\n\n    $ ./bin/fash.js get-vnodes 'tcp://3.moray.emy-11.joyent.us:2020' -l /var/tmp/rings/readme_sample -b leveldb\n    [ 4 ]\n\nSo now we would remap vnode `4`, this time to an existing pnode:\n\n    $ ./bin/fash.js remap-vnode -v 4 -b leveldb -p \"tcp://1.moray.emy-11.joyent.us:2020\" -l /var/tmp/rings/readme_sample -o\n    {\"tcp://1.moray.emy-11.joyent.us:2020\":\"4\"}\n    {\"vnodes\":6,\"pnodeToVnodeMap\":{\"tcp://1.moray.emy-11.joyent.us:2020\":{\"0\":1,\"2\":1,\"4\":\"ro\"},\"tcp://2.moray.emy-11.joyent.us:2020\":{\"1\":1,\"3\":1,\"5\":1}},\"algorithm\":{\"NAME\":\"sha256\",\"MAX\":\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\",\"VNODE_HASH_INTERVAL\":\"2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"2.1.0\"}\n\nAlthough it appears from that output that the vnode\n\"tcp://3.moray.emy-11.joyent.us:2020\" is already gone, that is not true.  This\nis because the LevelDB keys the [print-hash](#print) command uses to\ndisplay the LevelDB keys does not use the `/PNODE` key, which keeps track of\nall the pnodes in the ring.  This behavior is also present in [the -o flag available on some commands](#o-flag-commands). In any case, we can see the full list of the pnodes on the ring using [`get-pnodes`](#get-pnodes).\n<a name=\"sample-pnodes\"></a>\n\n    $ ./bin/fash.js get-pnodes -l /var/tmp/rings/readme_sample -b leveldb\n    [ 'tcp://1.moray.emy-11.joyent.us:2020',\n      'tcp://2.moray.emy-11.joyent.us:2020',\n      'tcp://3.moray.emy-11.joyent.us:2020' ]\n\nSo now we can remove the pnode from LevelDB:\n\n    $ ./bin/fash.js remove-pnode -p \"tcp://3.moray.emy-11.joyent.us:2020\" -b leveldb -l /var/tmp/rings/readme_sample -o\n    {\"vnodes\":6,\"pnodeToVnodeMap\":{\"tcp://1.moray.emy-11.joyent.us:2020\":{\"0\":1,\"2\":1,\"4\":\"ro\"},\"tcp://2.moray.emy-11.joyent.us:2020\":{\"1\":1,\"3\":1,\"5\":1}},\"algorithm\":{\"NAME\":\"sha256\",\"MAX\":\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\",\"VNODE_HASH_INTERVAL\":\"2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"2.1.0\"}\n\nAnd check that it's really gone:\n\n    $ ./bin/fash.js get-pnodes -l /var/tmp/rings/readme_sample -b leveldb\n    [ 'tcp://1.moray.emy-11.joyent.us:2020',\n       'tcp://2.moray.emy-11.joyent.us:2020' ]\n\n## LevelDB Schema\n\nThe key-value store that we use is called LevelDB.  For more information on how\nLevelDB works generally, see https://github.com/google/leveldb.  For\ninformation on the LevelDOWN library that serves as a Node.js binding for\nLevelDB, see https://github.com/level/leveldown/.\n\nIn fash's setup, we create the following keys to manipulate and describe the\nstructure (LevelDB key-value store) that underlies a ring topology (pnode-vnode\nmapping).  In the `leveldb.js` file, each of these are assigned to a constant\nvariable prefaced with `LKEY_` with `P` and `V` standing in for `%s` and `%d`.\nThe fact that the key names resemble file paths does not imply that a navigable\nfile system backs this structure. (For example, there is no key that\ncorresponds to `/VNODE`).\n\n```\n    KEY               VALUE\n```\n<a name=\"lkey_vnode_count\"></a>\n```\nVNODE_COUNT      |    The total number of vnodes in the ring\n```\n<a name=\"lkey_vnode_data\"></a>\n```\nVNODE_DATA       |    The array of vnodes that contain optional data\n```\n<a name=\"lkey_vnode_v\"></a>\n```\n/VNODE/%d        |    The pnode a given vnode (%d) is assigned to\n```\n<a name=\"lkey_pnodes\"></a>\n```\n/PNODE           |    The array of all pnodes in the hash ring\n```\n<a name=\"lkey_vnodes\"></a>\n```\n/PNODE/%s        |    The array of all vnodes that are assigned to the given pnode (%s)\n```\n<a name=\"lkey_data\"></a>\n```\n/PNODE/%s/%d     |    The value of the data on the given vnode (%d), which is on the given pnode (%s)\n```\n<a name=\"lkey_algorithm\"></a>\n```\nALGORITHM        |    The hashing algorithm used to create the ring topology\n```\n<a name=\"lkey_version\"></a>\n```\nVERSION          |    Supposedly the version of fash we are on -- at this time, hard-coded to 2.1.0\n```\n<a name=\"lkey_complete\"></a>\n```\nCOMPLETE         |    Essentially a flag that is set to 1 when the ring creation finishes\n```\n\n## LevelDB-supported CLI\n\nThe purpose of these descriptions is to identify and explain each command's\nrelationship to the LevelDB keys it needs to function.  Many of these are\nexplained in the context of their use in the [walkthrough](#walkthrough)\nsection.  This section will describe them in terms of their relationship to\nLevelDB.\n\n  * [`create`](#create)\n  * [`deserialize-ring`](#deserialize-ring)\n  * [`add-data`](#add-data)\n  * [`remap-vnode`](#remap-vnode)\n  * [`remove-pnode`](#remove-pnode)\n  * [`get-pnodes`](#get-pnodes)\n  * [`get-vnodes`](#get-vnodes)\n  * [`get-vnode-pnode-and-data`](#get-vnode-pnode-and-data)\n  * [`get-data-vnodes`](#get-data-vnodes)\n  * [`get-node`](#get-node)\n  * [`print-hash`](#print-hash)\n  * [`diff`](#diff)\n\n### create\n[Click here to see an example](#command-line-ring-creation)\n\n`create` opens the LevelDB database and populates all of the keys in the\nschema.  A step-by-step listing of the order in which the keys are populated is\nbelow:\n\n1. First, the count of vnodes is stored in [`VNODE_COUNT`](#lkey_vnode_count).\n2. In batches of 1000, each [`/VNODE/%d`](#lkey_vnode_v) key is written to its\ncorrespondent pnode.\n3. Each [`/PNODE/%s/%d`](#lkey_data) key is assigned the `LVAL_NULL` default\ndata value of `1`.\n4. The [`/PNODE/%s`](#lkey_vnodes) keys are written from the `pnodeToVnodeMap`\ncreated during the previous step, and the [`/PNODE`](#lkey_pnodes) array is\npopulated from the keys of the `pnodeMap` object created from the pnode options\npassed in this command.\n5. (and 6 and 7) The [`ALGORITHM`](#lkey_algorithm), [`VERSION`](#lkey_version),\nand [`COMPLETE`](#lkey_complete) keys are written -- the latter two hard-coded\nto default values.  The algorithm is taken from the options passed, and, if none\nare found, defaults to sha256.\n\nThe effect of this is to create a hash ring with a one-to-many relationship\nbetween pnodes and vnodes, and a one-to-one relationship between vnodes and the\ndata they hold.  The [LevelDB keys](#leveldb-schema) end up serving as a kind of\nmetadata for describing aspects of this structure.\n\n### deserialize-ring\n[Click here to see an example](#sample-deserialize)\n\n`deserialize-ring` takes a json representation of a topology from a file or\nstdin and turns it into a LevelDB data structure.  In this case, only the\nLevelDB keys used for accessing the underlying mappings will be written.  Since\nthe hashing has already necessarily completed in order to create the input\ngiven, [`ALGORITHM`](#lkey_algorithm), [`VERSION`](#lkey_version), and [`COMPLETE`](#lkey_complete)\ndo not need to be written. This command writes [`/VNODE/%d`](#lkey_vnode_v), [`/PNODE/%s/%d`](#lkey_data),\n[`/PNODE/%s`](#lkey_vnodes), and [`VNODE_DATA`](#lkey_vnode_data).\n\n### add-data\n[Click here to see an example](#adding-data-to-vnodes)\n\n`add-data` takes a vnode number and allows you to assign any data to it.  If\nthere is any use-case for which the consuming application needs to\ndifferentiate between arbitrary vnodes, assigning an identifiable data string\nto it is the way to do that.  The way it works is that the value of the key [`/PNODE/%s/%d`](#lkey_data)\nhas to be overwritten to contain the data you've passed, and the vnode chosen\nto put the data inside has to be added to the array stored in [`VNODE_DATA`](#lkey_vnode_data).\nTo access [`/PNODE/%s/%d`](#lkey_data), you need the pnode name.  The function\ndoes a lookup of the [`/VNODE/%d`](#lkey_vnode_v) key to find the pnode that\nthe vnode you passed in is assigned to, and then assigns the data to that key.\nFor [`VNODE_DATA`](#lkey_vnode_data), the function does a lookup of the current\nvalue of the key (an array `vnodeArray`), and if the chosen vnode isn't in that\narray, and the data is not null, it is pushed into `vnodeArray`, which is\nreassigned to [`VNODE_DATA`](#lkey_vnode_data).\n\n### remap-vnode\n[Click here to see an example](#remapping-vnodes)\n\n`remap-vnode` takes a list of vnodes (which can be just one vnode) and a\ntarget pnode, and moves those vnodes from their current location onto the\ntarget pnode.  This is a multi-step process that involves multiple LevelDB\nkeys.\n\n1. First there is an attempt to look up the vnodes under the target pnode using\nthe [`/PNODE/%s`](#lkey_vnodes) key, not to retrieve the\nlist of vnodes, but to see if a `NotFoundError` is generated.  By\nrecording this if/else in a boolean variable, this gives the rest of the\nfunction access to whether or not the pnode is a new or an existing one.\n2. Next there is a lookup on the [`/VNODE/%d`](#lkey_vnode_v)\nkey to retrieve the current pnode of the vnode(s) set to be remapped.  If the\ncurrent and intended pnode are the same, an error is thrown and the operation\nerrors out.\n3. Then there is a lookup of the [`/PNODE/%s/%d`](#lkey_data)\nkey to get the data on the vnode.\n4. Next the keys to assign data to the moving vnodes -- [`/PNODE/%s/%d`](#lkey_data)\n-- are deleted.  The vnodes for the old pnode are retrieved from the [`/PNODE/%s`](#lkey_vnodes) \nkey, then put into a batch for later.  Then, the [`/PNODE/%s/%d`](#lkey_data)\nkeys are deleted.\n5. The new vnodes-from-pnode mappings key ([`/PNODE/%s`](#lkey_vnodes)),\ndata keys ([`/PNODE/%s/%d`](#lkey_data)), and\npnode-from-vnode ([`/VNODE/%d`](#lkey_vnode_v)) are put\ninto batches to be committed as LevelDB keys in the final commit step.\n6. The new pnode is written to the [`/PNODE`](#lkey_pnodes) key.\n\n### remove-pnode\n[Click here to see an example](#removing-pnodes)\n\n`remove-pnode` checks that the [`/PNODE/%s`](#lkey_vnodes)\nkey exists, and if it has any vnodes.  If it has vnodes, it will ask the\noperator to re-assign those first.  If not, it will delete the the [`/PNODE/%s`](#lkey_vnodes)\nkey and alter the the [`/PNODE`](#lkey_pnodes) key's array so that it no longer\ncontains the pnode in question.\n\n### get-pnodes\n[Click here to see an example](##sample-pnodes)\n\n`get-pnodes` lists the array of pnodes in the hash ring.  It does this via a get\non the [`/PNODE`](#lkey_pnodes) key in LevelDB.\n\n### get-vnodes\n[Click here to see an example](#sample-vnodes)\n\n`get-vnodes` lists the array of vnodes in a given pnode in the hash ring.  It\ndoes this via a get on the [`/PNODE/%s`](#lkey_vnodes) key in LevelDB, where `%s`\nis the argument you pass to the `-p` flag when invoking this command.\n\n### get-vnode-pnode-and-data\n[Click here to see an example](#sample-datapv)\n\n`get-vnode-pnode-and-data` takes a (number of) vnode(s), and from that returns\nthe values of the pnode it is assigned to via the [`/VNODE/%d`](#lkey_vnode_v)\nkey and also the data it contains via the [`/PNODE/%s/%d`](#lkey_data) key.\n\n### get-data-vnodes\n[Click here to see an example](#sample-datav)\n\n`get-data-vnodes` returns the value of the [`VNODE_DATA`](#lkey_vnode_data) key.\nThis will return any vnode that has a value other than the default value of 1 --\nit cannot, at the time of writing, select on different data values held in\nvnodes.  However, it offers a verbose flag so that an operator can view the data\nheld within each vnode, as well as which pnode it is assigned to.  The keys used\nto accomplish this are those used in [`get-vnode-pnode-and-data`](get-vnode-pnode-and-data).\n\n### get-node\n[Click here to see an example](#sample-node)\n\n`get-node` takes a key, runs it through fash's deterministic hashing algorithm\nto determine the vnode it is on, and does a get on the [`/VNODE/%d`](#lkey_vnode_v)\nkey in LevelDB, which returns the pnode information needed to do a get on the [`/PNODE/%s/%d`](#lkey_data)\nkey in LevelDB, which gives back the data on the vnode and pnode derived from\nthe key.\n\n### print-hash\n[Click here to see an example](#sample-print)\n\n`print-hash` lets you view the hash ring topology.  This operation is also\ninvoked by passing the -o flag to the <a name='o-flag-commands'>commands</a>\n[create](#create), [add-data](#add-data), [remap-vnode](#remap-vnode), or [remove-pnode](#remove-pnode)\n-- but do so *WITH EXTREME CAUTION*. For large hash rings, such as those with a\nmillion or more vnodes, this operation will be extremely slow, or may not even\ncomplete.\n\n    ./bin/fash.js print-hash -l /var/tmp/rings/readme_sample -b leveldb\n    {\"vnodes\":6,\"pnodeToVnodeMap\":{\"tcp://1.moray.emy-11.joyent.us:2020\":{\"0\":1,\"2\":1,\"4\":\"ro\"},\"tcp://2.moray.emy-11.joyent.us:2020\":{\"1\":1,\"3\":1,\"5\":1}},\"algorithm\":{\"NAME\":\"sha256\",\"MAX\":\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\",\"VNODE_HASH_INTERVAL\":\"2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"version\":\"2.1.0\"}\n\n### diff\n[Click here to see an example](#sample-diff)\n\n`diff` shows certain differences between two hash ring topologies.  The first\ntopology you pass will be compared to the second -- bear this in mind for the\ndifferences returned will be in a format that uses the words \"added\" and\n\"removed.\"  In particular, the names of the pnodes in the ring, as well as the\nnumber and allocations of vnodes, will be compared.  **Data within each vnode\nwill be ignored.**  A sample return is below:\n\n    $ ./bin/fash.js diff -b leveldb /var/tmp/rings/sample1 /var/tmp/rings/sample2\n    {\"tcp://1.moray.emy-11.joyent.us:2020\":{\"added\":[20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99]}}\n\nIn terms of schema keys, the function gets the values of [`/PNODE`](#lkey_pnodes)\nfrom the two topologies passed to the command, then looks up the values of [`/PNODE/%s`](#lkey_vnodes)\nto get the complete set of data it compares.\n\n## Running Tests\n\nJust run `make prepush` or `make test`, first exporting the `DB_LOCATION`\nvariable for the load test file to give it the location of your hash ring.\n\nCopyright (c) 2017, Joyent, Inc.\n\nThis Source Code Form is subject to the terms of the Mozilla Public\nLicense, v. 2.0. If a copy of the MPL was not distributed with this\nfile, You can obtain one at http://mozilla.org/MPL/2.0/.\n","readmeFilename":"README.md","users":{"fgribreau":true,"shiningray":true,"shanewholloway":true}}