178 | * attachedSlots full的时候,throws Exception 179 | *180 | * 181 | * @return 182 | * @throws Exception 183 | */ 184 | public int nextCurrent() throws IndexOutofRangeException { 185 | 186 | int curr = current; 187 | 188 | incCurrent(); 189 | return curr + capacity; 190 | } 191 | 192 | /** 193 | * 在attachedSlots获取current值; 194 | * 因为一般在扩容的新的索引内存数据,不会有IndexOutOfRangeException 195 | * 196 | * @return 197 | */ 198 | public int nextCurrentSafely() { 199 | 200 | int oldIndex = current; 201 | current++; 202 | return oldIndex + capacity; 203 | } 204 | 205 | // 返回该内存索引的所有数据 206 | public byte[] Bytes() { 207 | 208 | return bytes; 209 | } 210 | 211 | // 写入capacity到bytes 212 | public IndexMemoryByte writeCapacity() { 213 | 214 | byte[] capacityBytes = NumberPacker.packInt(capacity); 215 | for (int i = 0; i < 4; i++) { 216 | bytes[i] = capacityBytes[i]; 217 | } 218 | 219 | return this; 220 | } 221 | 222 | // 写入attachedSlots用到哪一个slot 223 | public IndexMemoryByte writeCurrent() { 224 | 225 | byte[] currentBytes = NumberPacker.packInt(current); 226 | for (int i = 0; i < 4; i++) { 227 | bytes[i + 4] = currentBytes[i]; 228 | } 229 | 230 | return this; 231 | } 232 | 233 | // 释放相应的内存 234 | // to do: check it's fine or not to call system.gc() 235 | public void release() { 236 | 237 | bytes = null; 238 | System.gc(); 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/main/java/org/herDB/index/IndexOutofRangeException.java: -------------------------------------------------------------------------------- 1 | package org.herDB.index; 2 | 3 | /** 4 | * 内存索引的溢出异常, 5 | * 6 | * @author funeyu 7 | */ 8 | @SuppressWarnings("serial") 9 | public class IndexOutofRangeException extends Exception { 10 | 11 | public IndexOutofRangeException() { 12 | super("the IndexMemory is full and can't find any empty slot in attachedSlots"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/herDB/index/IndexSegment.java: -------------------------------------------------------------------------------- 1 | package org.herDB.index; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | import org.herDB.herdb.Configuration; 5 | import org.herDB.store.FSDirectory; 6 | import org.herDB.store.InputOutData; 7 | import org.herDB.utils.Bytes; 8 | import org.herDB.utils.Hash; 9 | import org.herDB.utils.NumberPacker; 10 | 11 | import java.io.IOException; 12 | import java.util.Arrays; 13 | import java.util.concurrent.locks.ReentrantLock; 14 | 15 | 16 | 17 | /** 18 | * 分片索引文件的类 19 | * 20 | * @author funeyu 21 | */ 22 | @SuppressWarnings("serial") 23 | public class IndexSegment extends ReentrantLock { 24 | 25 | private IndexMemoryByte indexMemoryByte; 26 | // 为文件的名称,这里索引文件与数据文件文件名称一致 27 | private String fileName; 28 | // todo: 放在configuration里 29 | // 索引文件的后缀 30 | private final static String INDEXSUFFIX = ".index"; 31 | // 数据文件的后缀 32 | private final static String DATASUFFIX = ".data"; 33 | // 临时文件的后缀名 34 | private final static String TEMFILESUFFIX = ".tep"; 35 | // 扩容不能超过的最大容量 36 | private final static int MAXSIZE = 2 << 26; 37 | // main.java.org.herDB.index io操作的入口类 38 | private InputOutData fsIndex; 39 | // data io操作的入口类 40 | private InputOutData fsData; 41 | // FSDirectory的门面 42 | private FSDirectory fsd; 43 | // 读取文件用到的文件块大小 默认先 64KB的大小 44 | private int BufferedSize = 1 << 10; 45 | 46 | /** 47 | * @param campacity 48 | * @param current 49 | * @param fileName 50 | * @param fs 51 | * @param fsData 52 | * @param fsd 53 | * @param isFirst 54 | */ 55 | private IndexSegment(int campacity, int current, String fileName, InputOutData fs, 56 | InputOutData fsData, FSDirectory fsd, boolean isFirst) { 57 | this.indexMemoryByte = isFirst ? IndexMemoryByte.init(campacity, current) : 58 | IndexMemoryByte.open(fsd.readIndexFully(fileName + INDEXSUFFIX)); 59 | this.fileName = fileName; 60 | this.fsIndex = fs; 61 | this.fsData = fsData; 62 | this.fsd = fsd; 63 | } 64 | 65 | /** 66 | * 根据FSDirectory创建或者打开IndexSegment,首次则创建IndexSegment, 67 | * 非首次则打开IndexSegment 68 | * 69 | * @param fsd 70 | * @param fileName 71 | * @return 72 | * @throws Exception 73 | */ 74 | public final static IndexSegment createIndex(FSDirectory fsd, String fileName, Configuration conf) 75 | throws Exception { 76 | 77 | boolean first = false; 78 | 79 | // index文件不存在则新建index文件 80 | if (!fsd.isExsit(fileName + INDEXSUFFIX) && (first = true)) 81 | fsd.touchFile(fileName + INDEXSUFFIX); 82 | InputOutData fsIndex = fsd.createDataStream(fileName + INDEXSUFFIX, false); 83 | 84 | if (!fsd.isExsit(fileName + DATASUFFIX)) 85 | fsd.touchFile(fileName + DATASUFFIX); 86 | InputOutData fsData = fsd.createDataStream(fileName + DATASUFFIX, conf.isOnlyRead()); 87 | 88 | if (first) { 89 | return new IndexSegment(conf.get(Configuration.SLOTS_CAPACITY), 0, fileName, fsIndex, 90 | fsData, fsd, true); 91 | } 92 | 93 | byte[] bytes = fsIndex.readFully(); 94 | return new IndexSegment(NumberPacker.unpackInt(Arrays.copyOfRange(bytes, 0, 4)), 95 | NumberPacker.unpackInt(Arrays.copyOfRange(bytes, 4, 8)), 96 | fileName, fsIndex, fsData, fsd, false); 97 | } 98 | 99 | 100 | /** 101 | * put操作的实现; 102 | *
itemData格式: itemData.length(4字节) + key.length(4字节) + key/value(n字节)252 | * 253 | * @param offset: itemData的开头 254 | * @return 255 | * @throws IOException 256 | */ 257 | private byte[] keyData(long offset) throws IOException { 258 | 259 | // 获取key数据的长度 260 | int keyLength = NumberPacker.unpackInt(fsData.seek(offset + 4, 4)); 261 | 262 | return fsData.readSequentially(keyLength); 263 | } 264 | 265 | /** 266 | * 索引文件达到full即attachedSlots没有可以再利用 需要扩容 267 | * 扩容的时候:从磁盘文件里顺序读取文件判断是否该数据被删除 268 | * 并写到另一个文件里 269 | * 270 | * @throws Exception 271 | */ 272 | private void resize() throws Exception { 273 | 274 | int newCap = 0; 275 | 276 | if ((newCap = indexMemoryByte.capacity() << 1) > MAXSIZE) { 277 | throw new IllegalArgumentException( 278 | "The comapacity:`" + newCap + "` is reaching its maxsize and can`t expend anymore"); 279 | } 280 | 281 | // 用来读文件的缓存的block 282 | ReadingBufferedBlock readingBlock = ReadingBufferedBlock.allocate(BufferedSize); 283 | // 用来写文件的缓存的block 284 | WritingBufferedBlock writingBlock = WritingBufferedBlock.allocate(BufferedSize); 285 | // 将写文件的缓存block的limit设置为最大 286 | writingBlock.setLimit(BufferedSize); 287 | 288 | // 文件用来写去除无用数据 289 | InputOutData temData = fsd.createDataStream(fileName + TEMFILESUFFIX, false); 290 | IndexMemoryByte tempMemoryByte = IndexMemoryByte.init(newCap, 0); 291 | 292 | // 每次resize之前,先将文件的指针置于开头的位置,便于从头开始顺序读 293 | fsData.jumpHeader(); 294 | while (readingBlock.placeHeader() 295 | .setLimit(fsData.readBlock(readingBlock.getBlock())) != -1) { 296 | byte[] resultData; 297 | while ((resultData = readingBlock.nextItem()) != null) { 298 | byte[] keyBytes = Bytes.extractKey(resultData); 299 | long Offset = Bytes.extractOffset(resultData); 300 | byte[] itemData = Bytes.extractItemData(resultData); 301 | 302 | // 有效的itemData数据,添加到writingBlock 303 | if (isItemValid(keyBytes, Offset)) { 304 | long newOffset = writingBlock.getOffset(); 305 | putOnExtension(keyBytes, newOffset, tempMemoryByte); 306 | 307 | if (writingBlock.hasRoomFor(itemData)) { 308 | writingBlock.wrap(itemData); 309 | } else { 310 | temData.append(writingBlock.flush()); 311 | writingBlock.wrap(itemData); 312 | } 313 | } 314 | } 315 | } 316 | temData.append(writingBlock.flush()); 317 | 318 | // 删除旧的文件 319 | fsData.deleteFile(); 320 | temData.reName(fileName + DATASUFFIX); 321 | fsData = temData; 322 | indexMemoryByte = tempMemoryByte; 323 | } 324 | 325 | /** 326 | * 不加锁的put 只在扩容或者campact的时候调用,添加新的索引信息 327 | * 328 | * @param key 存储的key 字节数组 329 | * @param offset rawdata在磁盘文件的偏移 330 | * @param indexMemory 另一内存索引用来扩充等等 331 | */ 332 | private void putOnExtension(byte[] key, long offset, IndexMemoryByte indexMemory) { 333 | 334 | int index = Hash.FNVHash1(key) & (indexMemory.capacity() - 1); 335 | int hc = Hash.KeyHash(key); 336 | // 标记最终的slot是否在attachedSlots里 337 | boolean isInAttached = false; 338 | 339 | if (indexMemory.getHashCode(index) != 0) { 340 | isInAttached = true; 341 | 342 | while (indexMemory.getAttachedSlot(index) != 0) { 343 | index = indexMemory.getAttachedSlot(index); 344 | } 345 | } 346 | 347 | // 新建slot, 并将slot的index 更新到上一个slot的attachedSlot 348 | if (isInAttached) { 349 | int newIndex = indexMemory.nextCurrentSafely(); 350 | indexMemory.setAttachedSlot(index, newIndex); 351 | indexMemory.replaceSlot(hc, offset, 0, newIndex); 352 | return; 353 | } 354 | indexMemory.replaceSlot(hc, offset, 0, index); 355 | } 356 | 357 | /** 358 | * 从磁盘读取每个item,并在索引内存里判断其是否有效 359 | * 360 | * @return true: 无效的item; false:有效的item 361 | */ 362 | private boolean isItemValid(byte[] key, long offset) { 363 | 364 | int index = Hash.FNVHash1(key) & indexMemoryByte.capacity() - 1; 365 | 366 | do { 367 | if (indexMemoryByte.getFilePosition(index) == offset) { 368 | return true; 369 | } 370 | } while ((index = indexMemoryByte.getAttachedSlot(index)) != 0); 371 | 372 | return false; 373 | } 374 | 375 | /** 376 | * 将内存的index文件flush到磁盘里 377 | */ 378 | private void close() { 379 | // 写入索引的容量值 attachedSlots用到的current值 380 | indexMemoryByte.writeCapacity() 381 | .writeCurrent(); 382 | 383 | try { 384 | fsIndex.deleteFile() 385 | .createNewFile() 386 | .flush(indexMemoryByte.Bytes()); 387 | } catch (IOException e) { 388 | 389 | e.printStackTrace(); 390 | } 391 | indexMemoryByte.release(); 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /src/main/java/org/herDB/index/ReadingBufferedBlock.java: -------------------------------------------------------------------------------- 1 | package org.herDB.index; 2 | 3 | import org.herDB.utils.Bytes; 4 | import org.herDB.utils.NumberPacker; 5 | 6 | import java.util.Arrays; 7 | 8 | 9 | public class ReadingBufferedBlock extends BufferedBlock { 10 | 11 | // item被分割在上一block的数据 12 | private byte[] splitedBytes; 13 | 14 | private ReadingBufferedBlock(int capacity, int position) { 15 | super(capacity, position); 16 | } 17 | 18 | public static ReadingBufferedBlock allocate(int capacity) { 19 | 20 | return new ReadingBufferedBlock(capacity, 0); 21 | } 22 | 23 | /** 24 | * 迭代取出block的item,每个item的格式: 25 | *
26 | * datalength | keylength | key | value29 | * 30 | * @return 若无则返回 null,有完整item 则返回 offset(5字节) + item的字节数组 31 | */ 32 | public byte[] nextItem() { 33 | 34 | byte[] itemBytes; 35 | //block的开头,要与之前的block的splitedBytes合并 36 | if (position == 0) { 37 | if (splitedBytes != null) { 38 | itemBytes = joinBytes(splitedBytes); 39 | return Bytes.join(NumberPacker.packLong(getOffset() - itemBytes.length), itemBytes); 40 | } 41 | } 42 | 43 | int itemLen; 44 | long offSetData = getOffset(); 45 | // 可以直接读取itemLen 46 | if (left() >= 4) { 47 | itemLen = getInt(); 48 | // 可以直接读取到完整的item数据 49 | if (left() >= itemLen) { 50 | byte[] itemLenBytes = NumberPacker.packInt(itemLen); 51 | byte[] keyValueBytes = getBytes(itemLen); 52 | return Bytes.join(NumberPacker.packLong(offSetData), Bytes.join(itemLenBytes, keyValueBytes)); 53 | } else { 54 | // 不能读取完整的item数据,返回null 55 | splitedBytes = Bytes.join(NumberPacker.packInt(itemLen), leftBytes()); 56 | 57 | return null; 58 | } 59 | } else { 60 | // 不能完整获取itemLen 61 | splitedBytes = leftBytes(); 62 | 63 | return null; 64 | } 65 | } 66 | 67 | // 根据splitedBytes 合并item 68 | private byte[] joinBytes(byte[] splitedBytes) { 69 | 70 | byte[] thisPieces; 71 | if (splitedBytes.length >= 4) { 72 | int itemLen = NumberPacker.unpackInt(new byte[]{ 73 | splitedBytes[0], 74 | splitedBytes[1], 75 | splitedBytes[2], 76 | splitedBytes[3] 77 | }); 78 | thisPieces = getBytes(itemLen - splitedBytes.length + 4); 79 | return Bytes.join(splitedBytes, thisPieces); 80 | } 81 | 82 | // 磁盘itemLen数据被分开在两个block,先组得出itemlen的数值 83 | int itemLen = NumberPacker.unpackInt( 84 | Bytes.join(splitedBytes, getBytes(4 - splitedBytes.length))); 85 | 86 | return Bytes.join(NumberPacker.packInt(itemLen), getBytes(itemLen)); 87 | } 88 | 89 | //获取当前position位置的int数字 90 | private int getInt() { 91 | 92 | int oldPosi = position; 93 | advance(4); 94 | return NumberPacker.unpackInt(new byte[]{ 95 | container[oldPosi], 96 | container[oldPosi + 1], 97 | container[oldPosi + 2], 98 | container[oldPosi + 3] 99 | }); 100 | } 101 | 102 | // 获取该缓冲长度为span的字节数组 103 | private byte[] getBytes(int span) { 104 | 105 | if (span == 0) { 106 | return null; 107 | } 108 | 109 | int oldPo = getPosition(); 110 | advance(span); 111 | return Arrays.copyOfRange(container, oldPo, oldPo + span); 112 | } 113 | 114 | /** 115 | * 返回剩余的字节数组 116 | * 117 | * @return 118 | */ 119 | private byte[] leftBytes() { 120 | 121 | // 说明没有剩余, item没被分在两个block里 122 | if (position == limit) { 123 | return null; 124 | } 125 | 126 | int temPo = position; 127 | advance(limit - position); 128 | return Arrays.copyOfRange(container, temPo, limit); 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/org/herDB/index/Slot.java: -------------------------------------------------------------------------------- 1 | package org.herDB.index; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.herDB.utils.NumberPacker; 6 | 7 | /** 8 | * 为哈希的槽节点相关的方法集合,每个slot实际上三步分组成 9 | *
27 | *datalength = 4 + key.length + value.length
28 | *
10 | * <--hashcode-->|<--fileposition-->|<--attachedslot--> 11 | * ----4字节-----------5字节----------------4字节-------- 12 | *13 | *
14 | * 此时的Slot相当于static unit class
15 | *
16 | * @author funeyu
17 | */
18 | public final class Slot {
19 | // 每个slot
20 | public final static int slotSize = (4 + 5 + 4);
21 |
22 | private Slot() {
23 | }
24 |
25 | ;
26 |
27 | /**
28 | * 由hc fp as三个参数去组装成一个byte[slotSize]
29 | *
30 | * @param hashcode
31 | * @param fileposition 5 byte长度的long数 最大值为 256^5 1T
32 | * @param attachedslot
33 | */
34 | public static byte[] generate(int hashcode, long fileposition, int attachedslot) {
35 |
36 | byte[] bytes = new byte[slotSize];
37 |
38 | byte[] hc = NumberPacker.packInt(hashcode);
39 | for (int i = 0; i < 4; i++)
40 | bytes[i] = hc[i];
41 |
42 | byte[] fp = NumberPacker.packLong(fileposition);
43 | for (int i = 0; i < 5; i++)
44 | bytes[i + 4] = fp[i];
45 |
46 | byte[] as = NumberPacker.packInt(attachedslot);
47 | for (int i = 0; i < 4; i++)
48 | bytes[i + 9] = as[i];
49 |
50 | return bytes;
51 | }
52 |
53 | /**
54 | * 设置索引号为slot的槽attachedSlot 值为attachedslot
55 | *
56 | * @param slot
57 | * @param attachedslot
58 | * @param bytes 为索引的全量内存数据
59 | */
60 | public static void setAttachedSlot(int slot, int attachedslot, byte[] bytes) {
61 |
62 | byte[] attach = NumberPacker.packInt(attachedslot);
63 | for (int i = 0; i < 4; i++) {
64 | bytes[slot * slotSize + 8 + 9 + i] = attach[i];
65 | }
66 | }
67 |
68 |
69 | /**
70 | * 获取该slot下 相对应key的hashcode
71 | *
72 | * @param bytes
73 | * @return
74 | */
75 | public static int getHashCode(byte[] bytes) {
76 |
77 | return NumberPacker.unpackInt(Arrays.copyOfRange(bytes, 0, 4));
78 | }
79 |
80 | /**
81 | * 获取hash索引某slots对应的file文件位置信息
82 | *
83 | * @param bytes
84 | * @return
85 | */
86 | public static long getFileInfo(byte[] bytes) {
87 |
88 | return NumberPacker.unpackLong(Arrays.copyOfRange(bytes, 4, 9));
89 | }
90 |
91 | /**
92 | * 获取该slot的后继slot的id
93 | *
94 | * @param bytes
95 | * @return
96 | */
97 | public static int getAttachedSlot(byte[] bytes) {
98 |
99 | return NumberPacker.unpackInt(Arrays.copyOfRange(bytes, 9, slotSize));
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/index/WritingBufferedBlock.java:
--------------------------------------------------------------------------------
1 | package org.herDB.index;
2 |
3 | import java.util.Arrays;
4 |
5 | public class WritingBufferedBlock extends BufferedBlock {
6 |
7 | private WritingBufferedBlock(int capacity, int position) {
8 | super(capacity, position);
9 | }
10 |
11 | public static WritingBufferedBlock allocate(int capacity) {
12 |
13 | return new WritingBufferedBlock(capacity, 0);
14 | }
15 |
16 | /**
17 | * 判断写block是否有空间 容纳itemData
18 | *
19 | * @param itemData key/value的数据
20 | * @return true 有空间, false 没空间
21 | */
22 | public boolean hasRoomFor(byte[] itemData) {
23 |
24 | if (left() >= itemData.length) {
25 | return true;
26 | }
27 | return false;
28 | }
29 |
30 | /**
31 | * 将文件缓冲读出,并将该文件缓冲置头
32 | *
33 | * @return
34 | */
35 | public byte[] flush() {
36 |
37 | int oldPo = position;
38 | placeHeader();
39 | return Arrays.copyOfRange(container, 0, oldPo);
40 | }
41 |
42 | /**
43 | * 将data的字节数组包装到该缓冲文件中
44 | *
45 | * @param data
46 | * @return
47 | */
48 | public BufferedBlock wrap(byte[] data) {
49 |
50 | if (data == null) {
51 | return this;
52 | }
53 |
54 | for (int i = 0, length = data.length; i < length; i++) {
55 | container[i + position] = data[i];
56 | }
57 |
58 | advance(data.length);
59 | return this;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/net/Client.java:
--------------------------------------------------------------------------------
1 | package org.herDB.net;
2 |
3 | import org.herDB.utils.Bytes;
4 | import org.herDB.utils.NumberPacker;
5 |
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.io.OutputStream;
9 | import java.net.Socket;
10 | import java.util.UUID;
11 |
12 | /**
13 | * Created by funeyu on 17/1/1.
14 | */
15 | public class Client {
16 |
17 | // 生成一个uuid标识该client;每次都将该id传送给server,用来校验等操作
18 | private String uuid ;
19 | private Socket socket;
20 | private InputStream in;
21 | private OutputStream os;
22 |
23 | private Client(Socket socket, String uuid, InputStream in, OutputStream os) {
24 | this.socket = socket;
25 | this.uuid = uuid;
26 | this.in = in;
27 | this.os = os;
28 | }
29 |
30 | public static Client initClient(int port, String host) throws IOException{
31 | Socket socket = new Socket(host, port);
32 | String uuid = UUID.randomUUID().toString();
33 | InputStream in = socket.getInputStream();
34 | OutputStream os = socket.getOutputStream();
35 | Client client = new Client(socket, uuid, in, os);
36 | return client;
37 | }
38 |
39 | public String get(String key) throws IOException{
40 | sendCommand(("get,"+ key).getBytes());
41 | return read();
42 | }
43 |
44 | public void put(String key, String value) {
45 | sendCommand(("put,"+ key + "," + value).getBytes());
46 | }
47 |
48 | public void auth(String token) throws IOException{
49 | sendCommand(("auth," + token).getBytes());
50 | String re = read();
51 | System.out.println(re);
52 | }
53 |
54 | public void close() {
55 | try {
56 | socket.close();
57 | } catch (IOException e) {
58 | e.printStackTrace();
59 | }
60 | }
61 |
62 | private void sendCommand(byte[] commandInfo) {
63 |
64 | byte[] callInfo = Bytes.join(uuid.getBytes(), Bytes.join(NumberPacker.packInt(commandInfo.length), commandInfo));
65 |
66 | try {
67 | os.write(callInfo);
68 | os.flush();
69 | } catch (IOException e) {
70 | e.printStackTrace();
71 | }
72 | }
73 |
74 | private String read() throws IOException{
75 | try {
76 | byte[] lenBytes = new byte[4];
77 | in.read(lenBytes);
78 | int bytesLen = NumberPacker.unpackInt(lenBytes);
79 | byte[] rawContent = new byte[bytesLen];
80 | in.read(rawContent);
81 | String result = new String(rawContent);
82 | return result;
83 |
84 | } catch (IOException e) {
85 | e.printStackTrace();
86 |
87 | return "error: " + e.toString();
88 | }
89 | }
90 |
91 | public static void main(String[]args) {
92 | System.out.println(UUID.randomUUID().toString());
93 | try {
94 | Client client = Client.initClient(8888, "127.0.0.1");
95 | client.auth("funer");
96 | Long start = System.currentTimeMillis();
97 | for(int i = 10000; i < 100000; i++) {
98 | client.put("fuheyu"+ i, "java c" + i);
99 | }
100 | Long end = System.currentTimeMillis();
101 | System.out.println((end-start) / 1000);
102 | // client.put("fuheyu", "java c art");
103 | System.out.println(client.get("fuheyu0"));
104 |
105 | client.close();
106 | // client.put("funer", "java, eclipse");
107 | // System.out.println(client.get("funer"));
108 | } catch (IOException e) {
109 | e.printStackTrace();
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/net/Commands.java:
--------------------------------------------------------------------------------
1 | package org.herDB.net;
2 |
3 |
4 | import org.herDB.herdb.HerDB;
5 |
6 | /**
7 | * Created by funeyu on 17/1/1.
8 | */
9 | public class Commands {
10 |
11 | public static String get(String key, HerDB dbStore) {
12 | return dbStore.get(key);
13 | }
14 |
15 | public static void put(String key, String value, HerDB dbStore) {
16 | dbStore.put(key, value);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/net/Server.java:
--------------------------------------------------------------------------------
1 | package org.herDB.net;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.ByteBuffer;
6 | import java.nio.ByteOrder;
7 | import java.nio.channels.SelectionKey;
8 | import java.nio.channels.Selector;
9 | import java.nio.channels.ServerSocketChannel;
10 | import java.nio.channels.SocketChannel;
11 | import java.util.Iterator;
12 | import java.util.concurrent.ConcurrentHashMap;
13 | import java.util.concurrent.atomic.AtomicBoolean;
14 |
15 | import org.herDB.herdb.HerDB;
16 | import org.herDB.utils.Bytes;
17 | import org.herDB.utils.NumberPacker;
18 |
19 | /**
20 | * Created by funeyu on 16/12/31.
21 | */
22 | public class Server {
23 |
24 | private int port;
25 | private static Server singleServer;
26 | private AtomicBoolean listenning = new AtomicBoolean(true);
27 | // 记录clients的认证信息
28 | private static ConcurrentHashMapfileName
的文件
68 | *
69 | * @param pathName
70 | * @return
71 | */
72 | public File touchFile(String fileName) {
73 |
74 | File newedFile = new File(directory.getPath() + File.separator + fileName);
75 | try {
76 | if (newedFile.createNewFile())
77 | return newedFile;
78 | } catch (IOException e) {
79 | e.printStackTrace();
80 | }
81 | return null;
82 | }
83 |
84 | /**
85 | * 将磁盘文件全部读到内存, 方法只用在索引文件
86 | *
87 | * @param name 文件名
88 | * @return 磁盘文件的字节数组
89 | */
90 | public byte[] readIndexFully(String name) {
91 | try {
92 | RandomAccessFile f = new RandomAccessFile(new File(directory, name), "r");
93 | int length = (int) f.length();
94 | byte[] data = new byte[length];
95 | f.readFully(data);
96 | f.close();
97 |
98 | return data;
99 | } catch (IOException e) {
100 |
101 | e.printStackTrace();
102 | }
103 | return null;
104 | }
105 |
106 | /**
107 | * 创建FSDirectory的 最后要将该目录锁定,不让有其他的进程操作数据库;
108 | *
109 | * @param directoryPath 指定的目录路径
110 | * @param delete 目录存在删除为true,不删除为false
111 | * @return 创建成功就返回FSDirectory实例
112 | * @throws IOException
113 | */
114 | public static FSDirectory create(String directoryPath, boolean delete) throws IOException {
115 |
116 | File file = new File(directoryPath);
117 | if (!file.exists()) {
118 | if (!file.mkdirs())
119 | throw new IOException("不能创建初始的文件夹:" + directoryPath);
120 | } else {
121 | // 这里有两个出错异常点:
122 | // 1,文件夹已经存在但是 delete为false的情况下,自定义的异常
123 | // 2,删除文件夹里所有的文件出现的系统IOException异常
124 | if (delete ? !deleteFiles(file) : true)
125 | throw new IOException("文件夹存在但是又不能删除或者删除出错:" + directoryPath);
126 | }
127 | return new FSDirectory(file).lockDir();
128 | }
129 |
130 | /**
131 | * 打开一个目录, 此目录必须是herDB的目录,如果有锁文件就throw exception 然后再进行枷锁的操作
132 | *
133 | * @param directoryPath 要打开的文件夹
134 | * @param onlyRead true:只读不写 false:读写
135 | * @return
136 | */
137 | public static FSDirectory open(String directoryPath) {
138 |
139 | File file = new File(directoryPath);
140 | if (!file.exists())
141 | return null;
142 | return new FSDirectory(file).lockDir();
143 | }
144 |
145 | /**
146 | * 目录下只有文件,没有二级的文件夹,删除目录里所有的文件 留着一个空的目录
147 | *
148 | * @param dir 将要删除文件的目录
149 | * @return 只要有一个删除不成功就返回false 全部删除完成返回true
150 | */
151 | public static boolean deleteFiles(File dir) {
152 |
153 | for (File f : dir.listFiles()) {
154 | if (!f.delete())
155 | return false;
156 | }
157 | return true;
158 | }
159 |
160 | /**
161 | * 通过FSDirectory创建FSDataStream,负责目录下所有的数据读写操作 包括index文件的读取,与rawData数据文件的读取
162 | *
163 | * @param name 该目录下的文件名
164 | * @return
165 | * @throws Exception
166 | * @onlyRead 只读:true, 读写:false
167 | * 在打开herdb数据库,只读情况下可以将数据文件映射到堆内存,加快读操作
168 | */
169 | public InputOutData createDataStream(String name, boolean onlyRead) throws Exception {
170 |
171 | return onlyRead ? new MMapInputStream(this.directory, name)
172 | : new FSDataStream(this.directory, name);
173 | }
174 |
175 | class FSDataStream extends InputOutData {
176 |
177 | private long length;
178 | private long maxOffSet;
179 | private String fileName;
180 | private File file;
181 | private File directory;
182 | private RandomAccessFile raf;
183 |
184 | public FSDataStream(File dir, String name) throws Exception {
185 |
186 | File f = new File(dir, name);
187 | file = f;
188 | directory = dir;
189 | fileName = name;
190 | raf = new RandomAccessFile(f, "rw");
191 | maxOffSet = length = raf.length();
192 |
193 | }
194 |
195 | public byte[] readFully() throws IOException {
196 |
197 | byte[] data = new byte[(int) length];
198 | raf.read(data);
199 | return data;
200 | }
201 |
202 | public void flush(byte[] datas) {
203 |
204 | try {
205 | raf.write(datas, 0, datas.length);
206 | } catch (IOException e) {
207 | e.printStackTrace();
208 | }
209 | }
210 |
211 | @Override
212 | public byte[] seek(long offset, int size) throws IOException {
213 |
214 | raf.seek(offset);
215 |
216 | byte[] res = new byte[size];
217 | if (raf.read(res) == -1)
218 | throw new EOFException();
219 |
220 | return res;
221 | }
222 |
223 | @Override
224 | public FSDataStream append(byte[] data) throws IOException {
225 |
226 | long fileLength = raf.length();
227 | raf.seek(fileLength);
228 | raf.write(data);
229 | maxOffSet += data.length;
230 | return this;
231 | }
232 |
233 | @Override
234 | public byte[] readSequentially(int size) throws IOException {
235 |
236 | byte[] bytes = new byte[size];
237 | raf.read(bytes);
238 | return bytes;
239 | }
240 |
241 | @Override
242 | public long maxOffSet() {
243 |
244 | return maxOffSet;
245 | }
246 |
247 | @Override
248 | public InputOutData position(long offset) throws IOException {
249 | this.raf.seek(offset);
250 | return this;
251 | }
252 |
253 | @Override
254 | public InputOutData deleteFile() {
255 | this.file.delete();
256 | return this;
257 | }
258 |
259 | @Override
260 | public InputOutData createNewFile() throws IOException {
261 |
262 | File f = new File(directory, fileName);
263 | file = f;
264 | raf = new RandomAccessFile(f, "rw");
265 | length = raf.length();
266 | return this;
267 | }
268 |
269 |
270 | @Override
271 | public int readBlock(byte[] block) throws IOException {
272 |
273 | return this.raf.read(block);
274 | }
275 |
276 | @Override
277 | public boolean reName(String newName) {
278 |
279 | File newFile = new File(directory, newName);
280 | boolean isok = file.renameTo(newFile);
281 | file = newFile;
282 |
283 | try {
284 | raf = new RandomAccessFile(file, "rw");
285 | length = raf.length();
286 | } catch (IOException e) {
287 | isok = false;
288 | e.printStackTrace();
289 | }
290 |
291 | return isok;
292 | }
293 |
294 | @Override
295 | public void jumpHeader() throws IOException {
296 |
297 | this.raf.seek(0);
298 | }
299 |
300 |
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/store/InputOutData.java:
--------------------------------------------------------------------------------
1 | package org.herDB.store;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * 文件读写涉及到的类
7 | *
8 | * @author fuheu
9 | */
10 |
11 | /**
12 | * @author funeyu
13 | *
14 | */
15 | public abstract class InputOutData {
16 |
17 | /**
18 | * 一次将文件所有的内容读入内存中
19 | *
20 | * @return 文件内容的字节数组
21 | */
22 | public abstract byte[] readFully() throws IOException;
23 |
24 | /**
25 | * 从文件offset开始处,随机读取length长度的字节数组
26 | *
27 | * @param offset
28 | * 开始读取的位置
29 | * @param length
30 | * 读取文件的长度
31 | * @return 读取到的字节数组
32 | */
33 | public abstract byte[] seek(long offset, int size) throws IOException;
34 |
35 | /**
36 | * 将内存中的flush到磁盘中
37 | *
38 | * @param data
39 | * 内存中的字节数组
40 | */
41 | public abstract void flush(byte[] data);
42 |
43 | /**
44 | * 从文件的末尾追加数据
45 | *
46 | * @param data
47 | * @return 追加完数据后
48 | */
49 | public abstract InputOutData append(byte[] data) throws IOException;
50 |
51 | /**
52 | * 顺序读取文件
53 | *
54 | * @param size 读取文件的长度
55 | * @return
56 | */
57 | public abstract byte[] readSequentially(int size) throws IOException;
58 |
59 | /**
60 | * 获取文件的offset
61 | *
62 | * @return
63 | */
64 | public abstract long maxOffSet();
65 |
66 | /**
67 | * 将文件的指针置于相应的位置
68 | * @param offset
69 | * @return
70 | */
71 | public abstract InputOutData position(long offset) throws IOException;
72 |
73 | /**
74 | * 清除该文件磁盘的所有内容
75 | */
76 | public abstract InputOutData deleteFile();
77 |
78 | /**
79 | * 新建文件
80 | * @return
81 | */
82 | public abstract InputOutData createNewFile() throws IOException;
83 |
84 | /**
85 | * 将该文件读写指针置于开头
86 | * @return
87 | */
88 | public abstract void jumpHeader() throws IOException;
89 |
90 | public abstract int readBlock(byte[] block) throws IOException;
91 |
92 | /**
93 | * 修改文件的名称为 newName
94 | * @param newName
95 | * @return
96 | */
97 | public abstract boolean reName(String newName);
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/store/Lock.java:
--------------------------------------------------------------------------------
1 | package org.herDB.store;
2 |
3 | public abstract class Lock {
4 | protected final static int INTERVAL = 1000;
5 |
6 | /**
7 | * 获取锁的方法,这里是一次尝试获取,若要多次尝试需写while循环
8 | *
9 | * @return
10 | */
11 | protected abstract boolean acquire();
12 |
13 | /**
14 | * 释放锁的方法,这里是一次释放就可以
15 | *
16 | * @return
17 | */
18 | public abstract void release();
19 |
20 | /**
21 | * 尝试多次获取锁,若经过仍没能获取成功就直接返回false
22 | *
23 | * @return
24 | * @throws Exception
25 | */
26 | public boolean lock(int lockWaitTimes) {
27 |
28 | int times = 0;
29 | while (++times < lockWaitTimes) {
30 | if (acquire())
31 | return true;
32 | try {
33 | Thread.sleep(INTERVAL);
34 | } catch (InterruptedException e) {
35 | e.printStackTrace();
36 | return false;
37 | }
38 | }
39 | return false;
40 | }
41 | }
--------------------------------------------------------------------------------
/src/main/java/org/herDB/store/MMapInputStream.java:
--------------------------------------------------------------------------------
1 | package org.herDB.store;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.io.RandomAccessFile;
6 | import java.nio.MappedByteBuffer;
7 | import java.nio.channels.FileChannel;
8 |
9 | import org.herDB.herdb.UnsupportedException;
10 |
11 |
12 | /**
13 | * 为了加快文件随机读的操作,将文件映射到内存中
14 | * 注意: 不能在又读又写的情况下开启映射文件,为了性能映射内存只映射一次, 不能根据文件的追加而实时改变内存;
15 | *
16 | * @author funeyu
17 | */
18 | public class MMapInputStream extends InputOutData {
19 |
20 | private MappedByteBuffer randomFile;
21 |
22 | @SuppressWarnings("resource")
23 | public MMapInputStream(File dir, String pathName) {
24 | File file = new File(dir, pathName);
25 | try {
26 | randomFile = new RandomAccessFile(file, "r").getChannel().map(FileChannel.MapMode.READ_ONLY, 0,
27 | file.length()).load();
28 | } catch (IOException e) {
29 | e.printStackTrace();
30 | }
31 | }
32 |
33 | // 不需要将磁盘文件全部读到内存中
34 | @Override
35 | public byte[] readFully() throws IOException {
36 |
37 | throw new UnsupportedException("readFully", this);
38 | }
39 |
40 | @Override
41 | public byte[] seek(long offset, int size) throws IOException {
42 |
43 | randomFile.position((int) offset);
44 | return null;
45 | }
46 |
47 | @Override
48 | public InputOutData append(byte[] data) throws IOException {
49 |
50 | throw new UnsupportedException("append", this);
51 | }
52 |
53 | @Override
54 | public void flush(byte[] data) {
55 |
56 | throw new UnsupportedException("flush", this);
57 | }
58 |
59 | @Override
60 | public byte[] readSequentially(int size) throws IOException {
61 |
62 | byte[] result = new byte[size];
63 | randomFile.get(result);
64 | return result;
65 | }
66 |
67 | @Override
68 | public long maxOffSet() {
69 |
70 | return randomFile.capacity();
71 | }
72 |
73 | @Override
74 | public InputOutData position(long offset) throws IOException {
75 |
76 | randomFile.position((int) offset);
77 | return this;
78 | }
79 |
80 | @Override
81 | public InputOutData deleteFile() {
82 |
83 | throw new UnsupportedException("deleteFile", this);
84 | }
85 |
86 | @Override
87 | public InputOutData createNewFile() throws IOException {
88 |
89 | throw new UnsupportedException("createNewFile", this);
90 | }
91 |
92 | @Override
93 | public int readBlock(byte[] block) {
94 |
95 | return randomFile.get(block).capacity();
96 | }
97 |
98 | @Override
99 | public boolean reName(String newName) {
100 |
101 | throw new UnsupportedException("reName", this);
102 | }
103 |
104 | @Override
105 | public void jumpHeader() throws IOException {
106 |
107 | randomFile.position(0);
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/utils/Bytes.java:
--------------------------------------------------------------------------------
1 | package org.herDB.utils;
2 |
3 | import java.util.Arrays;
4 |
5 | public final class Bytes {
6 |
7 | private Bytes() {
8 | }
9 |
10 | /**
11 | * 将数组the 与 other两个数组合并成一个数组并返回
12 | *
13 | * @param the
14 | * @param other
15 | * @return
16 | */
17 | public final static byte[] join(byte[] the, byte[] other) {
18 |
19 | if (the == null) {
20 | return other;
21 | }
22 | if (other == null) {
23 | return the;
24 | }
25 |
26 | byte[] result = new byte[the.length + other.length];
27 |
28 | for (int i = 0, length = the.length; i < length; i++) {
29 | result[i] = the[i];
30 | }
31 |
32 | for (int i = 0, theLength = the.length, otherLength = other.length; i < otherLength; i++) {
33 | result[theLength + i] = other[i];
34 | }
35 |
36 | return result;
37 | }
38 |
39 | /**
40 | * 将key 与 value打包成byte[]返回, 同时写入总长度
41 | * 格式为:datalength | keylength | key | value
42 | *
43 | * @param key
44 | * @param value
45 | * @return
46 | */
47 | public final static byte[] wrapData(byte[] key, byte[] value) {
48 |
49 | // 先写入该wrapedData的长度
50 | byte[] datalength = NumberPacker.packInt(key.length + value.length + 4);
51 | // 写入key的长度
52 | byte[] keylength = NumberPacker.packInt(key.length);
53 |
54 | return join(join(join(datalength, keylength), key), value);
55 | }
56 |
57 | /**
58 | * 从一个byte[]整体里得出key的具体内容,resultBytes格式:
59 | * offset(5 bytes) + itemlength(4 bytes) + keylen(4 bytes) + key/value(n bytes)
60 | *
61 | * @param resultBytes: Offset + itemData
62 | * @return key的bytes
63 | */
64 | public final static byte[] extractKey(byte[] resultBytes) {
65 | int keyLength = NumberPacker.unpackInt(new byte[]{
66 | resultBytes[9],
67 | resultBytes[10],
68 | resultBytes[11],
69 | resultBytes[12]
70 | });
71 |
72 | byte[] key = new byte[keyLength];
73 | for (int i = 0; i < keyLength; i++) {
74 | key[i] = resultBytes[13 + i];
75 | }
76 |
77 | return key;
78 | }
79 |
80 | /**
81 | * 从resultBytes得出offset数据
82 | *
83 | * @param resultBytes
84 | * @return
85 | */
86 | public final static long extractOffset(byte[] resultBytes) {
87 |
88 | return NumberPacker.unpackLong(new byte[]{
89 | resultBytes[0],
90 | resultBytes[1],
91 | resultBytes[2],
92 | resultBytes[3],
93 | resultBytes[4]
94 | });
95 | }
96 |
97 | /**
98 | * 从rsultsBytes得出itemData的数据
99 | *
100 | * @param resultBytes
101 | * @return
102 | */
103 | public final static byte[] extractItemData(byte[] resultBytes) {
104 |
105 | return Arrays.copyOfRange(resultBytes, 5, resultBytes.length);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/utils/Hash.java:
--------------------------------------------------------------------------------
1 | package org.herDB.utils;
2 |
3 | import java.util.Arrays;
4 |
5 | public class Hash {
6 | private final static int segmentSize = 7;
7 |
8 | private Hash() {
9 | }
10 |
11 | public static int FNVHash1(byte[] data) {
12 |
13 | final int p = 16777619;
14 | int hash = (int) 2166136261L;
15 | for (byte b : data)
16 | hash = (hash ^ b) * p;
17 | hash += hash << 13;
18 | hash ^= hash >> 7;
19 | hash += hash << 3;
20 | hash ^= hash >> 17;
21 | hash += hash << 5;
22 | return Math.abs(hash);
23 | }
24 |
25 | /**
26 | * 计算key的hashcode,为了内存索引数据中的hashcode字段 == 0判断该slot是否为空;
27 | * 需要将key的hashcode全部转成不等于0的数据;
28 | *
29 | * @param key
30 | * @return 不为0的数据
31 | */
32 | public static int KeyHash(byte[] key) {
33 |
34 | int hashcode = Arrays.hashCode(key);
35 | return hashcode == 0 ? 1 : hashcode;
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/herDB/utils/NumberPacker.java:
--------------------------------------------------------------------------------
1 | package org.herDB.utils;
2 |
3 | /**
4 | * number与byte array的互相转换的工具类 note:这里的转换int 与long型number都是non-negative的
5 | *
6 | * @author funeyu
7 | */
8 | public final class NumberPacker {
9 |
10 | private NumberPacker() {
11 | }
12 |
13 | /**
14 | * 将long型数字打包成字节数组
15 | *
16 | * @param ba long pack成的字节数组
17 | * @param value 需要pack的long
18 | * @return
19 | */
20 | public static byte[] packLong(long value) {
21 |
22 | byte[] ba = new byte[5];
23 | if (value < 0) {
24 | throw new IllegalArgumentException("negative value: v=" + value);
25 | }
26 |
27 | int i = 1;
28 | while ((value & ~0x7FL) != 0) {
29 | ba[i - 1] = (byte) (((int) value & 0x7F) | 0x80);
30 | value >>>= 7;
31 | i++;
32 | }
33 | ba[i - 1] = (byte) value;
34 | return ba;
35 | }
36 |
37 | /**
38 | * 将一定的字节数组解包成long数字
39 | *
40 | * @param bytes
41 | * @return
42 | */
43 | public static long unpackLong(byte[] bytes) {
44 |
45 | long result = 0;
46 | int index = 0;
47 | for (int offset = 0; offset < 64; offset += 7) {
48 | long b = bytes[index++];
49 | result |= (b & 0x7F) << offset;
50 | if ((b & 0x80) == 0) {
51 | return result;
52 | }
53 | }
54 | throw new Error("Malformed long.");
55 | }
56 |
57 | /**
58 | * 将字符数组转换成int
59 | *
60 | * @param bytes
61 | * @return int
62 | */
63 | public static int unpackInt(byte[] bytes) {
64 |
65 | int result = 0;
66 | for (int i = 0; i < 4; i++) {
67 | result |= ((bytes[i] & 0xFF) << (4 - 1 - i) * 8);
68 | }
69 |
70 | return result;
71 | }
72 |
73 | /**
74 | * 将int number转换成字节数组
75 | *
76 | * @param number
77 | * @return 长度为4的字节数组
78 | */
79 | public static byte[] packInt(int value) {
80 |
81 | byte[] ba = new byte[4];
82 |
83 | for (int i = 0; i < 4; i++) {
84 | ba[i] = (byte) ((value >> 8 * (4 - 1 - i)) & 0xFF);
85 | }
86 | return ba;
87 | }
88 |
89 | public static void main(String[] args) {
90 | byte[] bytes = packInt(698446115);
91 | System.out.println(unpackInt(bytes));
92 |
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/test/getTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by fuheyu on 2018/6/8.
3 | */
4 | import org.herDB.herdb.Configuration;
5 | import org.herDB.herdb.HerDB;
6 | import org.junit.Assert;
7 | import org.junit.BeforeClass;
8 | import org.junit.Test;
9 |
10 | /**
11 | * Created by fuheyu on 2018/6/8.
12 | */
13 | public class getTest {
14 |
15 |
16 | @Test
17 | public void getTest() throws Exception {
18 |
19 | HerDB herDB = HerDB.openOnlyRead("herdb");
20 | String v = herDB.get("java");
21 | Assert.assertEquals("eclipse", v);
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/src/main/test/putbyteTest.java:
--------------------------------------------------------------------------------
1 | import com.sun.deploy.util.SystemUtils;
2 | import org.herDB.herdb.Configuration;
3 | import org.herDB.herdb.HerDB;
4 | import org.junit.Assert;
5 | import org.junit.BeforeClass;
6 | import org.junit.Test;
7 |
8 | /**
9 | * Created by fuheyu on 2018/6/8.
10 | */
11 | public class putbyteTest {
12 |
13 | private static Configuration config;
14 | private static HerDB herDB;
15 |
16 | @BeforeClass
17 | public static void setUpConfig() throws Exception {
18 | config = Configuration.create("herdb");
19 |
20 | // 初始的情况下,slots的数组的大小
21 | config.set(Configuration.SLOTS_CAPACITY, "65536");
22 |
23 | // 设置读写缓冲块的大小
24 | config.set(Configuration.BUFFERED_BLOCK_SIZE, "8192");
25 |
26 | // 设置key/value数据的最大长度
27 | config.set(Configuration.ITEM_DATA_MAX_SIZE, "1024");
28 |
29 | herDB = HerDB.create(config, "herdb");
30 | }
31 |
32 | @Test
33 | public void putTest() {
34 | herDB.put("java", "eclipse");
35 | herDB.put("javaddddddd", "iajofdja;jfoa");
36 | herDB.commit();
37 | }
38 |
39 | @Test
40 | public void putRate() {
41 |
42 | long start = System.currentTimeMillis();
43 |
44 | for(int i = 0; i < 1024 * 1024 * 10; i ++) {
45 | herDB.put("java"+ i, "javajavassssss" + i);
46 | }
47 |
48 | herDB.commit();
49 |
50 | long end = System.currentTimeMillis();
51 |
52 | System.out.println("time:" + (end -start) / 1000 );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/target/classes/org/herDB/cache/StorageCache$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/cache/StorageCache$1.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/cache/StorageCache$NoCache.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/cache/StorageCache$NoCache.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/cache/StorageCache.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/cache/StorageCache.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/herdb/Configuration.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/herdb/Configuration.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/herdb/HerDB.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/herdb/HerDB.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/herdb/UnsupportedException.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/herdb/UnsupportedException.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/index/BufferedBlock.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/index/BufferedBlock.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/index/IndexMemoryByte.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/index/IndexMemoryByte.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/index/IndexOutofRangeException.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/index/IndexOutofRangeException.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/index/IndexSegment.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/index/IndexSegment.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/index/ReadingBufferedBlock.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/index/ReadingBufferedBlock.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/index/Slot.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/index/Slot.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/index/WritingBufferedBlock.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/index/WritingBufferedBlock.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/net/Client.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/net/Client.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/net/Commands.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/net/Commands.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/net/Server$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/net/Server$1.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/net/Server$Listenner.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/net/Server$Listenner.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/net/Server.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/net/Server.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/PrimitiveType$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/PrimitiveType$1.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/PrimitiveType$2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/PrimitiveType$2.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/PrimitiveType$3.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/PrimitiveType$3.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/PrimitiveType$4.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/PrimitiveType$4.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/PrimitiveType$5.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/PrimitiveType$5.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/PrimitiveType$6.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/PrimitiveType$6.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/PrimitiveType.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/PrimitiveType.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/Reflection.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/Reflection.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/Serializer.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/Serializer.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/SerializerImp$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/SerializerImp$1.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/SerializerImp$StringSerializer.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/SerializerImp$StringSerializer.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/SerializerImp.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/SerializerImp.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/serializer/SerializerUtils.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/serializer/SerializerUtils.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/store/FSDirectory$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/store/FSDirectory$1.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/store/FSDirectory$FSDataStream.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/store/FSDirectory$FSDataStream.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/store/FSDirectory.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/store/FSDirectory.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/store/InputOutData.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/store/InputOutData.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/store/Lock.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/store/Lock.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/store/MMapInputStream.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/store/MMapInputStream.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/utils/Bytes.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/utils/Bytes.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/utils/Hash.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/utils/Hash.class
--------------------------------------------------------------------------------
/target/classes/org/herDB/utils/NumberPacker.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/classes/org/herDB/utils/NumberPacker.class
--------------------------------------------------------------------------------
/target/test-classes/getTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/test-classes/getTest.class
--------------------------------------------------------------------------------
/target/test-classes/putbyteTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funeyu/herDB/7f6dd64db2c806cb3ef8bbf88e72600c8a31283a/target/test-classes/putbyteTest.class
--------------------------------------------------------------------------------