1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
| private static final int MAX_DATA_LENGTH = 1020; private static final byte[] ZERO_BYTES = new byte[MAX_DATA_LENGTH]; private static final String DATA_SUFFIX = ".data"; private static final String META_SUFFIX = ".meta";
Map<String, Long> indexMap; Queue<Long> gaps;
RandomAccessFile db; File metaFile;
public BasicDB(String path, String name) throws IOException { File dataFile = new File(path + name + DATA_SUFFIX); db = new RandomAccessFile(dataFile, "rw"); if(metaFile.exist()) { loadMeta(); } else { indexMap = new HashMap<> (); gaps = new ArrayDeque(); } }
public void put(String key, byte[] value) throws IOException { Long index = indexMap.get(key); if(index == null) { index = nextAvailablePos(); indexMap.put(key, index); } writeData(index, value); }
private long nextAvailablePos() throws IOException { if(!gaps.isEmpty()) { return gaps.poll(); } else { return db.length; } }
private void writeData(long pos, byte[] data) throws IOException { if(data.length > MAX_DATA_LENGTH) { throw new IllgalArgumentException("maximum allowed length is " + MAX_DATA_LENGTH + ", data length is " + data.length); } db.seek(pos); db.writeInt(data.length); db.write(data); db.write(ZERO_BYTES, 0, MAX_DATA_LENGTH - data.length); }
public byte[] get(String key) throws IOException { Long index = indexMap.get(key); if(index != null) { return getData(index); } return null; }
private byte[] getData(long pos) throws IOException { db.seek(pos); int length = db.readInt(); byte[] data = new byte[length]; db.readFully(data); return data; }
public void remove(String key) { Long index = indexMap.remove(key); if(index != null) { gaps.offer(index); } }
public void flush() throws IOException { saveMeta(); db.getFD().sync(); }
private void saveMeta() throws IOException { DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(metaFile))); try { saveIndex(out); saveGaps(out); } finally { out.close(); } }
private void saveIndex(DataOutputStream out) throws IOException { out.writeInt(indexMap.size()); for(Map.Entry<String, Long> entry : indexMap.entrySet()) { out.writeUTF(entry.getKey()); out.writeLong(entry.getValue()); } }
private void saveGaps(DataoutputStream out) throws IOException { out.writeInt(gaps.size()); for(Long pos : gaps) { out.writeLong(pos); } }
private void loadMeta() throws IOException { DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(metaFile)); try { loadIndex(in); loadGaps(in); } finally { in.close(); } }
private void loadIndex() throws IOException { int size = in.readInt(); indexMap = new HashMap<String, Long> ((int) (size / 0.75f) + 1, 0.75f); for(int i=0; i<size; i++) { String key = in.readUTF(); long index = in.readLong(); indexMap.put(key, index); } }
private void loadGaps(DataInputStream in) throws IOException { int size = in.readInt(); gaps = new ArrayDeque<> (size); for(int i = 0; i<size; i++) { long index = in.readLong(); gaps.add(index); } }
public void close() throws IOException { flush(); db.close(); }
|