├── .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