├── .gitignore ├── README.md ├── pom.xml └── src ├── demo └── java │ ├── Demo.java │ └── Test.java └── main └── java └── com └── udpwork └── ssdb ├── Link.java ├── MemoryStream.java ├── Response.java └── SSDB.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.class 4 | .DS_Store 5 | *.pyc 6 | *.swp 7 | *_cpy_* 8 | .project 9 | .classpath 10 | target 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | javassdb 2 | ======== 3 | 4 | SSDB Java client 5 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.updwork 6 | ssdb 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | ssdb 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/demo/java/Demo.java: -------------------------------------------------------------------------------- 1 | import com.udpwork.ssdb.*; 2 | 3 | /** 4 | * SSDB Java client SDK demo. 5 | */ 6 | public class Demo { 7 | public static void main(String[] args) throws Exception { 8 | SSDB ssdb = null; 9 | Response resp; 10 | byte[] b; 11 | ssdb = new SSDB("127.0.0.1", 8888); 12 | System.out.println("---- connected -----"); 13 | 14 | // 注意: 如果某个命令没有对应的函数, 你就使用 request() 方法来执行 15 | resp = ssdb.request("qpush", "q", "a"); 16 | for(int i=1; i 0){ 25 | sock.setSoTimeout(timeout_ms); 26 | } 27 | sock.setTcpNoDelay(true); 28 | } 29 | 30 | public void close(){ 31 | try{ 32 | sock.close(); 33 | }catch(Exception e){ 34 | // 35 | } 36 | } 37 | 38 | public Response request(String cmd, byte[]...params) throws Exception{ 39 | ArrayList list = new ArrayList(); 40 | for(byte[] s : params){ 41 | list.add(s); 42 | } 43 | return this.request(cmd, list); 44 | } 45 | 46 | public Response request(String cmd, String...params) throws Exception{ 47 | ArrayList list = new ArrayList(); 48 | for(String s : params){ 49 | list.add(s.getBytes()); 50 | } 51 | return this.request(cmd, list); 52 | } 53 | 54 | public Response request(String cmd, List params) throws Exception{ 55 | MemoryStream buf = new MemoryStream(4096); 56 | Integer len = cmd.length(); 57 | buf.write(len.toString()); 58 | buf.write('\n'); 59 | buf.write(cmd); 60 | buf.write('\n'); 61 | for(byte[] bs : params){ 62 | len = bs.length; 63 | buf.write(len.toString()); 64 | buf.write('\n'); 65 | buf.write(bs); 66 | buf.write('\n'); 67 | } 68 | buf.write('\n'); 69 | send(buf); 70 | 71 | List list = recv(); 72 | return new Response(list); 73 | } 74 | 75 | private void send(MemoryStream buf) throws Exception{ 76 | OutputStream os = sock.getOutputStream(); 77 | os.write(buf.toArray()); 78 | os.flush(); 79 | } 80 | 81 | private List recv() throws Exception{ 82 | input.nice(); 83 | InputStream is = sock.getInputStream(); 84 | while(true){ 85 | List ret = parse(); 86 | if(ret != null){ 87 | return ret; 88 | } 89 | byte[] bs = new byte[8192]; 90 | int len = is.read(bs); 91 | //System.out.println("<< " + (new MemoryStream(bs, 0, len)).printable()); 92 | input.write(bs, 0, len); 93 | } 94 | } 95 | 96 | public void testRead(byte[] data) throws Exception{ 97 | input.write(data, 0, data.length); 98 | System.out.println("<< " +input.repr()); 99 | 100 | List ret = parse(); 101 | if(ret != null){ 102 | System.out.println("---------------------"); 103 | for (byte[] bs : ret) { 104 | System.out.println(String.format("%-15s", MemoryStream.repr(bs))); 105 | } 106 | } 107 | } 108 | 109 | private List parse() throws Exception{ 110 | ArrayList list = new ArrayList(); 111 | 112 | int idx = 0; 113 | // ignore leading empty lines 114 | while(idx < input.size && (input.chatAt(idx) == '\r' || input.chatAt(idx) == '\n')){ 115 | idx ++; 116 | } 117 | 118 | while(idx < input.size){ 119 | int data_idx = input.memchr('\n', idx); 120 | if(data_idx == -1){ 121 | break; 122 | } 123 | data_idx += 1; 124 | 125 | int head_len = data_idx - idx; 126 | if(head_len == 1 || (head_len == 2 && input.chatAt(idx) == '\r')){ 127 | input.decr(data_idx); 128 | return list; 129 | } 130 | String str = new String(input.copyOfRange(idx, data_idx)); 131 | str = str.trim(); 132 | int size; 133 | try{ 134 | size = Integer.parseInt(str, 10); 135 | }catch(Exception e){ 136 | throw new Exception("Parse body_len error"); 137 | } 138 | 139 | idx = data_idx + size; 140 | 141 | int left = input.size - idx; 142 | if(left >= 1 && input.chatAt(idx) == '\n'){ 143 | idx += 1; 144 | }else if(left >= 2 && input.chatAt(idx) == '\r' && input.chatAt(idx+1) == '\n'){ 145 | idx += 2; 146 | }else if(left >= 2){ 147 | throw new Exception("bad format"); 148 | }else{ 149 | break; 150 | } 151 | // System.out.println("size: " + size + " idx: " + idx + " left: " + (input.size - idx)); 152 | 153 | byte[] data = input.copyOfRange(data_idx, data_idx + size); 154 | //System.out.println("size: " + size + " data: " + data.length); 155 | list.add(data); 156 | } 157 | return null; 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/udpwork/ssdb/MemoryStream.java: -------------------------------------------------------------------------------- 1 | package com.udpwork.ssdb; 2 | 3 | import java.util.Arrays; 4 | 5 | public class MemoryStream { 6 | private int capacity; 7 | private int data = 0; 8 | private int slot = 0; 9 | public int size = 0; 10 | public byte[] buf; 11 | 12 | public MemoryStream(){ 13 | this(4096); 14 | } 15 | 16 | public MemoryStream(int capacity){ 17 | this.capacity = capacity; 18 | buf = new byte[capacity]; 19 | } 20 | 21 | public MemoryStream(byte[] copy){ 22 | this(copy, 0, copy.length); 23 | } 24 | 25 | public MemoryStream(byte[] copy, int off, int len){ 26 | this.capacity = len; 27 | this.size = len; 28 | buf = Arrays.copyOfRange(copy, off, off + len); 29 | } 30 | 31 | public byte[] toArray(){ 32 | byte[] ret = Arrays.copyOfRange(buf, data, data + size); 33 | return ret; 34 | } 35 | 36 | public static String repr(byte[] bs){ 37 | StringBuffer sb = new StringBuffer(); 38 | for(int i=0; i space()){ 69 | capacity *= 2; 70 | buf = Arrays.copyOf(buf, capacity); 71 | } 72 | } 73 | 74 | public void nice(){ 75 | if(data > capacity/2){ 76 | System.arraycopy(buf, data, buf, 0, size); 77 | data = 0; 78 | slot = size; 79 | } 80 | } 81 | 82 | public void decr(int num){ 83 | size -= num; 84 | data += num; 85 | } 86 | 87 | public void write(int b){ 88 | this.write((byte)b); 89 | } 90 | 91 | public void write(byte b){ 92 | realloc(1); 93 | buf[size] = b; 94 | size += 1; 95 | slot += 1; 96 | } 97 | 98 | public void write(String s){ 99 | this.write(s.getBytes()); 100 | } 101 | 102 | public void write(byte[] bs){ 103 | this.write(bs, 0, bs.length); 104 | } 105 | 106 | public void write(byte[] bs, int start, int len){ 107 | realloc(len); 108 | System.arraycopy(bs, start, buf, slot, len); 109 | size += len; 110 | slot += len; 111 | } 112 | 113 | public int memchr(int b, int offset){ 114 | return this.memchr((byte)b, offset); 115 | } 116 | 117 | // return offset to data 118 | public int memchr(byte b, int offset){ 119 | for(int i=data+offset; i raw; 11 | /** 12 | * Indicates items' order 13 | */ 14 | public List keys = new ArrayList(); 15 | /** 16 | * key-value results 17 | */ 18 | public Map items = new LinkedHashMap(); 19 | 20 | public Response(List raw){ 21 | this.raw = raw; 22 | if(raw.size() > 0){ 23 | status = new String(raw.get(0)); 24 | } 25 | } 26 | 27 | public Object exception() throws Exception{ 28 | if(raw.size() >= 2){ 29 | throw new Exception(new String(raw.get(1))); 30 | }else{ 31 | throw new Exception(""); 32 | } 33 | } 34 | 35 | public boolean ok(){ 36 | return status.equals("ok"); 37 | } 38 | 39 | public boolean not_found(){ 40 | return status.equals("not_found"); 41 | } 42 | 43 | public void buildMap(){ 44 | for(int i=1; i+1 10 | * SSDB ssdb = new SSDB("127.0.0.1", 8888); 11 | * ssdb.set("a", "123"); 12 | * byte[] val = ssdb.get("a"); 13 | * ssdb.close(); 14 | * 15 | */ 16 | public class SSDB{ 17 | public Link link; 18 | 19 | public SSDB(String host, int port) throws Exception{ 20 | this(host, port, 0); 21 | } 22 | 23 | public SSDB(String host, int port, int timeout_ms) throws Exception{ 24 | link = new Link(host, port, timeout_ms); 25 | } 26 | 27 | public void close(){ 28 | link.close(); 29 | } 30 | 31 | public Response request(String cmd, byte[]...params) throws Exception{ 32 | return link.request(cmd, params); 33 | } 34 | 35 | public Response request(String cmd, String...params) throws Exception{ 36 | return link.request(cmd, params); 37 | } 38 | 39 | public Response request(String cmd, List params) throws Exception{ 40 | return link.request(cmd, params); 41 | } 42 | 43 | /* auth */ 44 | 45 | public void auth(String password) throws Exception{ 46 | Response resp = link.request("auth", password); 47 | if(resp.ok()){ 48 | return; 49 | } 50 | resp.exception(); 51 | } 52 | 53 | /* kv */ 54 | 55 | public void set(byte[] key, byte[] val) throws Exception{ 56 | Response resp = link.request("set", key, val); 57 | if(resp.ok()){ 58 | return; 59 | } 60 | resp.exception(); 61 | } 62 | 63 | public void set(String key, byte[] val) throws Exception{ 64 | set(key.getBytes(), val); 65 | } 66 | 67 | public void set(String key, String val) throws Exception{ 68 | set(key, val.getBytes()); 69 | } 70 | 71 | public void del(byte[] key) throws Exception{ 72 | Response resp = link.request("del", key); 73 | if(resp.ok()){ 74 | return; 75 | } 76 | resp.exception(); 77 | } 78 | 79 | public void del(String key) throws Exception{ 80 | del(key.getBytes()); 81 | } 82 | 83 | /*** 84 | * 85 | * @param key 86 | * @return null if not found 87 | * @throws Exception 88 | */ 89 | public byte[] get(byte[] key) throws Exception{ 90 | Response resp = link.request("get", key); 91 | if(resp.not_found()){ 92 | return null; 93 | } 94 | if(resp.raw.size() != 2){ 95 | throw new Exception("Invalid response"); 96 | } 97 | if(resp.ok()){ 98 | return resp.raw.get(1); 99 | } 100 | resp.exception(); 101 | return null; 102 | } 103 | 104 | /*** 105 | * 106 | * @param key 107 | * @return null if not found 108 | * @throws Exception 109 | */ 110 | public byte[] get(String key) throws Exception{ 111 | return get(key.getBytes()); 112 | } 113 | 114 | private Response _scan(String cmd, String key_start, String key_end, int limit) throws Exception{ 115 | if(key_start == null){ 116 | key_start = ""; 117 | } 118 | if(key_end == null){ 119 | key_end = ""; 120 | } 121 | Response resp = link.request(cmd, key_start, key_end, (new Integer(limit)).toString()); 122 | if(!resp.ok()){ 123 | resp.exception(); 124 | } 125 | resp.buildMap(); 126 | return resp; 127 | } 128 | 129 | public Response scan(String key_start, String key_end, int limit) throws Exception{ 130 | return _scan("scan", key_start, key_end, limit); 131 | } 132 | 133 | public Response rscan(String key_start, String key_end, int limit) throws Exception{ 134 | return _scan("rscan", key_start, key_end, limit); 135 | } 136 | 137 | public long incr(String key, long by) throws Exception{ 138 | Response resp = link.request("incr", key, (new Long(by)).toString()); 139 | if(!resp.ok()){ 140 | resp.exception(); 141 | } 142 | if(resp.raw.size() != 2){ 143 | throw new Exception("Invalid response"); 144 | } 145 | long ret = 0; 146 | ret = Long.parseLong(new String(resp.raw.get(1))); 147 | return ret; 148 | } 149 | 150 | /* hashmap */ 151 | 152 | public void hset(String name, byte[] key, byte[] val) throws Exception{ 153 | Response resp = link.request("hset", name.getBytes(), key, val); 154 | if(resp.ok()){ 155 | return; 156 | } 157 | resp.exception(); 158 | } 159 | 160 | public void hset(String name, String key, byte[] val) throws Exception{ 161 | this.hset(name, key.getBytes(), val); 162 | } 163 | 164 | public void hset(String name, String key, String val) throws Exception{ 165 | this.hset(name, key, val.getBytes()); 166 | } 167 | 168 | public void hdel(String name, byte[] key) throws Exception{ 169 | Response resp = link.request("hdel", name.getBytes(), key); 170 | if(resp.ok()){ 171 | return; 172 | } 173 | resp.exception(); 174 | } 175 | 176 | public void hdel(String name, String key) throws Exception{ 177 | this.hdel(name, key.getBytes()); 178 | } 179 | 180 | /** 181 | * 182 | * @param name 183 | * @param key 184 | * @return null if not found 185 | * @throws Exception 186 | */ 187 | public byte[] hget(String name, byte[] key) throws Exception{ 188 | Response resp = link.request("hget", name.getBytes(), key); 189 | if(resp.not_found()){ 190 | return null; 191 | } 192 | if(resp.raw.size() != 2){ 193 | throw new Exception("Invalid response"); 194 | } 195 | if(resp.ok()){ 196 | return resp.raw.get(1); 197 | } 198 | resp.exception(); 199 | return null; 200 | } 201 | 202 | /** 203 | * 204 | * @param name 205 | * @param key 206 | * @return null if not found 207 | * @throws Exception 208 | */ 209 | public byte[] hget(String name, String key) throws Exception{ 210 | return hget(name, key.getBytes()); 211 | } 212 | 213 | private Response _hscan(String cmd, String name, String key_start, String key_end, int limit) throws Exception{ 214 | if(key_start == null){ 215 | key_start = ""; 216 | } 217 | if(key_end == null){ 218 | key_end = ""; 219 | } 220 | Response resp = link.request(cmd, name, key_start, key_end, (new Integer(limit)).toString()); 221 | if(!resp.ok()){ 222 | resp.exception(); 223 | } 224 | for(int i=1; i