1
1
package org .voile ;
2
2
3
- import java .io .*;
3
+ import java .io .ByteArrayOutputStream ;
4
+ import java .io .File ;
5
+ import java .io .IOException ;
6
+ import java .io .ObjectInputStream ;
7
+ import java .io .ObjectOutputStream ;
8
+ import java .io .RandomAccessFile ;
9
+ import java .io .Serializable ;
4
10
import java .nio .ByteBuffer ;
5
11
import java .nio .channels .FileChannel ;
6
- import java .util .*;
12
+ import java .util .ArrayList ;
13
+ import java .util .Collections ;
14
+ import java .util .Comparator ;
15
+ import java .util .HashMap ;
16
+ import java .util .Set ;
17
+ import java .util .logging .Level ;
18
+ import java .util .logging .Logger ;
19
+
7
20
import org .voile .MemoryPool .Block ;
8
21
9
22
/**
12
25
public class VoileFile <K extends Serializable , V extends Serializable > {
13
26
14
27
private static final int INT_SIZE = Integer .SIZE / Byte .SIZE ;
15
- private static final int INDEX_ENTRY_SIZE = INT_SIZE + INT_SIZE + INT_SIZE ;
28
+ private static final int INDEX_ENTRY_SIZE = 3 * INT_SIZE ;
16
29
17
- private static final int INDEX_START = INT_SIZE + INT_SIZE ;
30
+ private static final int INDEX_START = 2 * INT_SIZE ;
18
31
19
32
private static final Comparator <Entry > dataPointerComparator = new Comparator <Entry >() {
20
33
@ Override
@@ -43,11 +56,13 @@ public VoileFile(File f) throws IOException {
43
56
updateMainHeader ();
44
57
}
45
58
else {
59
+ // read existing file
46
60
final int numEntries = file .readInt ();
47
61
final int dataStartPointer = file .readInt ();
48
62
49
63
ArrayList <Entry > entry_list = new ArrayList <Entry >(numEntries );
50
64
65
+ // read index, numEntries x (dataPointer, dataLength, keySize)
51
66
for (int i = 0 ; i < numEntries ; i ++) {
52
67
Block header = new Block ((int ) file .getFilePointer (), INDEX_ENTRY_SIZE );
53
68
Block data = new Block (file .readInt (), file .readInt ());
@@ -65,6 +80,8 @@ public VoileFile(File f) throws IOException {
65
80
int end = (int ) file .length ();
66
81
dataSpace = new MemoryPool (end , end , true );
67
82
83
+ // re-construct the free space pool based on the
84
+ // holes missing between the index entries
68
85
Collections .sort (entry_list , dataPointerComparator );
69
86
int d_pos = dataStartPointer ;
70
87
for (Entry e : entry_list ) {
@@ -92,30 +109,34 @@ public V put(K key, V value) throws IOException {
92
109
Entry e = index .get (key );
93
110
ByteBuffer key_data = object2bin (key );
94
111
ByteBuffer value_data = object2bin (value );
95
- System .err .println ("put key[" + key + "] [" + value + "]" );
96
- V old_value = null ;
97
112
98
- if ( e != null ) { // update
113
+ Logger . getLogger ( this . getClass (). getName ()). log ( Level . INFO , "put key[{0}] [{1}]" , new Object []{ key , value });
99
114
100
- //noinspection unchecked
101
- old_value = (V ) bin2object (readValue (e ));
115
+ V old_value = null ;
102
116
103
- // we got enough space to update ?
117
+ // if there's already a entry at this key
118
+ if (e != null ) {
119
+
120
+ // if we got enough space, update
104
121
if (value_data .remaining () + e .keySize <= e .data .length ) {
105
122
106
- // split the block
107
- Block nb = e .data .split (value_data .remaining () + e .keySize );
123
+ //noinspection unchecked
124
+ old_value = (V ) bin2object (readValue (e )); // get old value first
125
+
126
+ // split the data block
127
+ Block [] split_block = Block .splitBlock (e .data , value_data .remaining () + e .keySize );
108
128
109
- dataSpace .free (e .data ); // free old
110
- e .data = nb ; // store new block
111
-
129
+ dataSpace .free (split_block [1 ]); // free extra space
130
+ e .data = split_block [0 ]; // store new block
131
+
132
+ // write new data
112
133
chan .write (value_data , e .data .start + e .keySize );
113
134
writeEntry (e );
135
+
114
136
return old_value ;
115
137
}
116
- // else, need remove-insert again
117
- System .err .print ("put--" );
118
- remove (key );
138
+ // else, we need to remove and then insert again
139
+ old_value = remove (key );
119
140
}
120
141
// insert new
121
142
@@ -148,7 +169,7 @@ public V remove(K key) throws IOException {
148
169
final Entry e = index .get (key );
149
170
if (e == null ) return null ;
150
171
151
- System . err . println ( "remove [" + key + "]" );
172
+ Logger . getLogger ( this . getClass (). getName ()). log ( Level . INFO , "remove [{0}]" , key );
152
173
153
174
@ SuppressWarnings ({"unchecked" })
154
175
V old_value = (V ) bin2object (readValue (e ));
@@ -186,6 +207,7 @@ private void removeEntry(Entry e) throws IOException {
186
207
headerSpace .free (last_p );
187
208
}
188
209
210
+
189
211
private void updateMainHeader () throws IOException {
190
212
file .seek (0 );
191
213
file .writeInt (index .size ());
@@ -199,33 +221,26 @@ private Entry allocate(int keySize, int valueSize) throws IOException {
199
221
freeHeaderSpace ();
200
222
Block header = headerSpace .allocate (INDEX_ENTRY_SIZE );
201
223
Block data = dataSpace .allocate (size );
202
- Entry e = new Entry (header , data , keySize );
203
- //e.header = header;
204
- //e.data = data;
205
- return e ;
224
+ return new Entry (header , data , keySize );
206
225
}
207
226
208
227
private void freeHeaderSpace () throws IOException {
209
228
while (!headerSpace .checkSpace (INDEX_ENTRY_SIZE )) {
210
229
Entry f = findBlockAt (headerSpace .getLimit ());
211
230
212
231
if (f == null ) { // freed maybe ?
213
- System .err .println (dataSpace );
214
- System .err .println (headerSpace );
215
232
Block b = dataSpace .allocateAt (headerSpace .getLimit ());
216
233
217
234
if (b != null ) {
218
235
headerSpace .free (b ); // pass the space to the header
219
- System .err .println ("found on data " + b );
220
236
continue ;
221
237
} else {
222
- throw new IOException ("LOL " );
238
+ throw new IOException ("Corrupted: Couldn't get extra space for the header. " );
223
239
}
224
240
}
225
241
226
242
// find a new place to the data
227
243
Block data = dataSpace .allocate (f .data .length );
228
- int dp = data .start ;
229
244
230
245
// read the data
231
246
ByteBuffer key_data = readKey (f );
@@ -243,9 +258,7 @@ private void freeHeaderSpace() throws IOException {
243
258
}
244
259
245
260
private Entry findBlockAt (int targetFp ) {
246
- System .err .println ("target " + targetFp );
247
261
for (Entry e : index .values ()) {
248
- System .err .println (e .data .start + " " + e .data .length );
249
262
if (e .data .start == targetFp ) return e ;
250
263
}
251
264
return null ;
@@ -277,12 +290,12 @@ private ByteBuffer readValue(Entry e) throws IOException {
277
290
return value_data ;
278
291
}
279
292
280
- private ByteBuffer object2bin (Serializable o ) {
293
+ private ByteBuffer object2bin (Serializable o ) throws IOException {
281
294
ByteArrayOutputStream bao = new ByteArrayOutputStream ();
282
295
try {
283
296
new ObjectOutputStream (bao ).writeObject (o );
284
- } catch (IOException ignored ) {
285
- return null ;
297
+ } catch (IOException ex ) {
298
+ throw ex ;
286
299
}
287
300
return ByteBuffer .wrap (bao .toByteArray ());
288
301
}
@@ -292,10 +305,9 @@ private Serializable bin2object(ByteBuffer blob) throws IOException {
292
305
293
306
try {
294
307
return (Serializable ) new ObjectInputStream (new ByteBufferInputStream (blob )).readObject ();
295
- } catch (ClassNotFoundException ignored ) {
296
- ignored . printStackTrace (); //TODO: is this a problem ?
308
+ } catch (ClassNotFoundException cnfe ) {
309
+ throw new RuntimeException ( cnfe );
297
310
}
298
- return null ;
299
311
}
300
312
301
313
static class Entry {
0 commit comments