diff --git a/src/main/java/org/warp/jcwdb/CacheIndexManager.java b/src/main/java/org/warp/jcwdb/CacheIndexManager.java index 9a3f082..0044158 100644 --- a/src/main/java/org/warp/jcwdb/CacheIndexManager.java +++ b/src/main/java/org/warp/jcwdb/CacheIndexManager.java @@ -11,33 +11,40 @@ public class CacheIndexManager implements IndexManager { @Override public T get(long index, DBReader reader) { + // TODO: implement return null; } @Override - public int getType(long index) throws IOException { - // TODO Auto-generated method stub + public int getType(long index) { + // TODO: implement + return 0; + } + + @Override + public long add(DBDataOutput writer) { + // TODO: implement return 0; } @Override public void set(long index, DBDataOutput writer) { - + // TODO: implement } @Override public void delete(long index) { - + // TODO: implement } @Override public boolean has(long index) { + // TODO: implement return false; } @Override - public void close() throws IOException { - // TODO Auto-generated method stub - + public void close() { + // TODO: implement } } diff --git a/src/main/java/org/warp/jcwdb/Castable.java b/src/main/java/org/warp/jcwdb/Castable.java index bc5c336..23e04ed 100644 --- a/src/main/java/org/warp/jcwdb/Castable.java +++ b/src/main/java/org/warp/jcwdb/Castable.java @@ -1,5 +1,5 @@ package org.warp.jcwdb; public interface Castable { - public T cast(); + T cast(); } diff --git a/src/main/java/org/warp/jcwdb/DBDataOutput.java b/src/main/java/org/warp/jcwdb/DBDataOutput.java index 719ddcf..ef20a51 100644 --- a/src/main/java/org/warp/jcwdb/DBDataOutput.java +++ b/src/main/java/org/warp/jcwdb/DBDataOutput.java @@ -1,11 +1,11 @@ package org.warp.jcwdb; public interface DBDataOutput { - public int getSize(); - public int getType(); - public DBWriter getWriter(); + int getSize(); + int getType(); + DBWriter getWriter(); - public static DBDataOutput create(DBWriter writer, int type, int size) { + static DBDataOutput create(DBWriter writer, int type, int size) { return new DBDataOutput() { @Override diff --git a/src/main/java/org/warp/jcwdb/DBLightListParser.java b/src/main/java/org/warp/jcwdb/DBLightListParser.java new file mode 100644 index 0000000..7828463 --- /dev/null +++ b/src/main/java/org/warp/jcwdb/DBLightListParser.java @@ -0,0 +1,36 @@ +package org.warp.jcwdb; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.io.Output; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class DBLightListParser extends DBTypeParserImpl { + private static final Kryo kryo = new Kryo(); + private final JCWDatabase db; + + public DBLightListParser(JCWDatabase db) { + this.db = db; + } + + public DBReader getReader() { + return (i) -> { + ArrayList internalList = (ArrayList) kryo.readClassAndObject(i); + return new LightList(db, internalList); + }; + } + + public DBDataOutput getWriter(final LightList value) { + // TODO: optimize by writing longs directly, to make length determinable without writing to memory the output. + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Output out = new Output(baos); + kryo.writeClassAndObject(out, value.internalList); + out.close(); + byte[] b = baos.toByteArray(); + return DBDataOutput.create((o) -> { + o.write(b); + }, DBStandardTypes.STRING, b.length); + } +} diff --git a/src/main/java/org/warp/jcwdb/DBReader.java b/src/main/java/org/warp/jcwdb/DBReader.java index 0f8ef31..8b707ac 100644 --- a/src/main/java/org/warp/jcwdb/DBReader.java +++ b/src/main/java/org/warp/jcwdb/DBReader.java @@ -3,5 +3,5 @@ package org.warp.jcwdb; import com.esotericsoftware.kryo.io.Input; public interface DBReader { - public T read(Input i); + T read(Input i); } diff --git a/src/main/java/org/warp/jcwdb/DBStandardTypes.java b/src/main/java/org/warp/jcwdb/DBStandardTypes.java index 8dcf5e2..954b626 100644 --- a/src/main/java/org/warp/jcwdb/DBStandardTypes.java +++ b/src/main/java/org/warp/jcwdb/DBStandardTypes.java @@ -1,18 +1,20 @@ package org.warp.jcwdb; public class DBStandardTypes { - private static final int STD = 0xFFFFF000; - public static final int BOOLEAN = STD| 0; - public static final int BYTE = STD| 1; - public static final int SHORT = STD| 2; - public static final int CHAR = STD| 3; - public static final int INTEGER = STD| 4; - public static final int FLOAT = STD| 5; - public static final int DOUBLE = STD| 6; - public static final int STRING = STD| 7; + private static final int STD = 0xFFFFF000; + public static final int BOOLEAN = STD| 0; + public static final int BYTE = STD| 1; + public static final int SHORT = STD| 2; + public static final int CHAR = STD| 3; + public static final int INTEGER = STD| 4; + public static final int FLOAT = STD| 5; + public static final int DOUBLE = STD| 6; + public static final int STRING = STD| 7; public static final int BYTE_ARRAY = STD| 8; + public static final int LIGHT_LIST = STD| 9; - public static void registerStandardTypes(TypesManager typesManager) { - typesManager.registerType(STRING, new DBStringParser()); + public static void registerStandardTypes(JCWDatabase db, TypesManager typesManager) { + typesManager.registerType(String.class, STRING, new DBStringParser()); + typesManager.registerType(LightList.class, LIGHT_LIST, new DBLightListParser(db)); } } diff --git a/src/main/java/org/warp/jcwdb/DBTypeParser.java b/src/main/java/org/warp/jcwdb/DBTypeParser.java index 3fa53f8..12d8750 100644 --- a/src/main/java/org/warp/jcwdb/DBTypeParser.java +++ b/src/main/java/org/warp/jcwdb/DBTypeParser.java @@ -1,6 +1,6 @@ package org.warp.jcwdb; public interface DBTypeParser extends Castable { - public DBReader getReader(); - public DBDataOutput getWriter(final T value); + DBReader getReader(); + DBDataOutput getWriter(final T value); } diff --git a/src/main/java/org/warp/jcwdb/DBWriter.java b/src/main/java/org/warp/jcwdb/DBWriter.java index 7944e37..5456c58 100644 --- a/src/main/java/org/warp/jcwdb/DBWriter.java +++ b/src/main/java/org/warp/jcwdb/DBWriter.java @@ -3,5 +3,5 @@ package org.warp.jcwdb; import com.esotericsoftware.kryo.io.Output; public interface DBWriter { - public void write(Output o); + void write(Output o); } diff --git a/src/main/java/org/warp/jcwdb/EntryReference.java b/src/main/java/org/warp/jcwdb/EntryReference.java index d10d122..345f804 100644 --- a/src/main/java/org/warp/jcwdb/EntryReference.java +++ b/src/main/java/org/warp/jcwdb/EntryReference.java @@ -2,20 +2,58 @@ package org.warp.jcwdb; import java.io.IOException; -public class EntryReference { +/** + * You must have only a maximum of 1 reference for each index + * @param + */ +public class EntryReference implements Castable, AutoCloseable { private final JCWDatabase db; - private final long entryId; + private final long entryIndex; private final DBTypeParser parser; public T value; + private volatile boolean closed; + private final Object closeLock = new Object(); public EntryReference(JCWDatabase db, long entryId, DBTypeParser parser) throws IOException { this.db = db; - this.entryId = entryId; + this.entryIndex = entryId; this.parser = parser; - this.value = db.getIndexManager().get(entryId, parser.getReader()); + this.value = db.indices.get(entryId, parser.getReader()); + } + + public DBTypeParser getParser() { + return parser; + } + + public long getIndex() { + return entryIndex; } public void save() throws IOException { - db.getIndexManager().set(entryId, parser.getWriter(value)); + if (!closed) { + db.indices.set(entryIndex, parser.getWriter(value)); + } + } + + @Override + public T cast() { + return (T) this; + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + synchronized (closeLock) { + if (closed) { + return; + } + + db.removeEntryReference(entryIndex); + save(); + + closed = true; + } } } diff --git a/src/main/java/org/warp/jcwdb/FileAllocator.java b/src/main/java/org/warp/jcwdb/FileAllocator.java index c12e56a..031bc36 100644 --- a/src/main/java/org/warp/jcwdb/FileAllocator.java +++ b/src/main/java/org/warp/jcwdb/FileAllocator.java @@ -10,7 +10,7 @@ import java.nio.channels.FileChannel; import java.nio.channels.SeekableByteChannel; import java.util.*; -public class FileAllocator { +public class FileAllocator implements AutoCloseable { private final SeekableByteChannel dataFileChannel; private volatile long allocableOffset; private volatile boolean closed; @@ -24,7 +24,6 @@ public class FileAllocator { /** * TODO: not implemented * @param size - * @param type * @return offset */ public long allocate(int size) { diff --git a/src/main/java/org/warp/jcwdb/FileIndexManager.java b/src/main/java/org/warp/jcwdb/FileIndexManager.java index 6ac772e..990963e 100644 --- a/src/main/java/org/warp/jcwdb/FileIndexManager.java +++ b/src/main/java/org/warp/jcwdb/FileIndexManager.java @@ -3,8 +3,6 @@ package org.warp.jcwdb; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Channels; @@ -33,15 +31,18 @@ public class FileIndexManager implements IndexManager { /** * Edit this using editIndex() */ - private final Set dirtyLoadedIndices; + private final Set dirtyLoadedIndices, removedIndices; + private long firstAllocableIndex; public FileIndexManager(TypesManager typesManager, Path dataFile, Path metadataFile) throws IOException { this.typesManager = typesManager; loadedIndices = new HashMap<>(); dirtyLoadedIndices = new HashSet<>(); + removedIndices = new HashSet<>(); dataFileChannel = Files.newByteChannel(dataFile, StandardOpenOption.CREATE); metadataFileChannel = Files.newByteChannel(metadataFile, StandardOpenOption.CREATE); fileAllocator = new FileAllocator(dataFileChannel); + firstAllocableIndex = metadataFileChannel.size() / (long) IndexDetails.TOTAL_BYTES; } @Override @@ -62,7 +63,7 @@ public class FileIndexManager implements IndexManager { @Override public void set(long index, DBDataOutput data) throws IOException { checkClosed(); - IndexDetails indexDetails = getIndexMetadataUnsafe(index); + final IndexDetails indexDetails = getIndexMetadataUnsafe(index); if (indexDetails == null || indexDetails.getSize() < data.getSize()) { allocateAndWrite(index, data); } else { @@ -70,13 +71,43 @@ public class FileIndexManager implements IndexManager { editIndex(index, indexDetails.getOffset(), data.getSize(), indexDetails.getType()); fileAllocator.markFree(indexDetails.getOffset()+data.getSize(), data.getSize()); } - write(index, indexDetails, data); + writeExact(indexDetails, data); } } - private void write(final long index, final IndexDetails indexDetails, DBDataOutput data) throws IOException { + @Override + public long add(DBDataOutput data) throws IOException { + checkClosed(); + final int size = data.getSize(); + final long offset = fileAllocator.allocate(size); + final int type = data.getType(); + final IndexDetails indexDetails = new IndexDetails(offset, size, type); + final long index = createIndexMetadata(indexDetails); + writeExact(indexDetails, data); + return index; + } + + private long createIndexMetadata(IndexDetails indexDetails) { + long newIndex = firstAllocableIndex++; + loadedIndices.put(newIndex, indexDetails); + dirtyLoadedIndices.add(newIndex); + removedIndices.remove(newIndex); + return newIndex; + } + + /** + * Write the data at index. + * The input size must be equal to the index size! + * @param indexDetails + * @param data + * @throws IOException + */ + private void writeExact(final IndexDetails indexDetails, DBDataOutput data) throws IOException { + if (indexDetails.getSize() != data.getSize()) { + throw new IOException("Unable to write " + data.getSize() + " in a space of " + indexDetails.getSize()); + } final long offset = indexDetails.getOffset(); - + final Output o = new Output(Channels.newOutputStream(dataFileChannel.position(offset))); data.getWriter().write(o); o.close(); @@ -87,19 +118,30 @@ public class FileIndexManager implements IndexManager { final int type = w.getType(); final long offset = fileAllocator.allocate(size); IndexDetails details = editIndex(index, offset, size, type); - write(index, details, w); + writeExact(details, w); } @Override - public void delete(long index) { + public void delete(long index) throws IOException { checkClosed(); - + IndexDetails indexDetails = getIndexMetadataUnsafe(index); + if (indexDetails != null) { + fileAllocator.markFree(indexDetails.getOffset(), indexDetails.getSize()); + } + dirtyLoadedIndices.remove(index); + loadedIndices.remove(index); + removedIndices.add(index); } @Override public boolean has(long index) { checkClosed(); - return false; + try { + return getIndexMetadataUnsafe(index) != null; + } catch (IOException ex) { + ex.printStackTrace(); + return false; + } } private IndexDetails editIndex(long index, long offset, int size, int type) { @@ -108,14 +150,30 @@ public class FileIndexManager implements IndexManager { return indexDetails; } - private IndexDetails getIndexMetadataUnsafe(long index) { + private IndexDetails getIndexMetadataUnsafe(long index) throws IOException { + // Return index details if loaded IndexDetails details = loadedIndices.getOrDefault(index, null); if (details != null) return details; - - // TODO: implement index loading from file + + // Try to load the details from file + SeekableByteChannel currentMetadataFileChannel = metadataFileChannel.position(index * IndexDetails.TOTAL_BYTES); + ByteBuffer currentMetadataByteBuffer = ByteBuffer.allocateDirect(IndexDetails.TOTAL_BYTES); + currentMetadataFileChannel.read(currentMetadataByteBuffer); + currentMetadataByteBuffer.flip(); + // If it's not deleted continue + if ((currentMetadataByteBuffer.get() & IndexDetails.MASK_DELETED) == 0) { + final long offset = currentMetadataByteBuffer.getLong(); + final int size = currentMetadataByteBuffer.getInt(); + final int type = currentMetadataByteBuffer.getInt(); + final IndexDetails indexDetails = new IndexDetails(offset, size, type); + editIndex(index, indexDetails); + return indexDetails; + } + + // No results found. Returning null return null; } - + private IndexDetails getIndexMetadata(long index) throws IOException { IndexDetails details = getIndexMetadataUnsafe(index); if (details == null) @@ -141,6 +199,7 @@ public class FileIndexManager implements IndexManager { closed = true; } + // Update indices metadata SeekableByteChannel metadata = metadataFileChannel; ByteBuffer metadataEntryBuffer = ByteBuffer.allocateDirect(IndexDetails.TOTAL_BYTES); long lastIndex = -2; @@ -149,12 +208,23 @@ public class FileIndexManager implements IndexManager { if (index - lastIndex != 1) { metadata = metadata.position(index * IndexDetails.TOTAL_BYTES); } + metadataEntryBuffer.put((byte) 0); metadataEntryBuffer.putLong(indexDetails.getOffset()); metadataEntryBuffer.putInt(indexDetails.getSize()); metadataEntryBuffer.putInt(indexDetails.getType()); + metadataEntryBuffer.flip(); metadata.write(metadataEntryBuffer); lastIndex = index; } + + // Remove removed indices + ByteBuffer updatedMaskBuffer = ByteBuffer.allocateDirect(1); + for (Long index : removedIndices) { + metadata = metadata.position(index * IndexDetails.TOTAL_BYTES); + updatedMaskBuffer.put(IndexDetails.MASK_DELETED); + updatedMaskBuffer.flip(); + metadata.write(updatedMaskBuffer); + } fileAllocator.close(); } diff --git a/src/main/java/org/warp/jcwdb/IndexDetails.java b/src/main/java/org/warp/jcwdb/IndexDetails.java index 5f43b0b..50521e4 100644 --- a/src/main/java/org/warp/jcwdb/IndexDetails.java +++ b/src/main/java/org/warp/jcwdb/IndexDetails.java @@ -3,10 +3,15 @@ package org.warp.jcwdb; import java.util.Objects; public class IndexDetails { + /** + * The bitmask is used to determine if an index has been deleted + */ + public static final int BITMASK = 1; // 1 byte public static final int OFFSET_BYTES = Long.SIZE; public static final int DATA_SIZE_BYTES = Integer.SIZE; public static final int TYPE_BYTES = Integer.SIZE; - public static final int TOTAL_BYTES = OFFSET_BYTES + DATA_SIZE_BYTES + TYPE_BYTES; + public static final int TOTAL_BYTES = BITMASK + OFFSET_BYTES + DATA_SIZE_BYTES + TYPE_BYTES; + public static final byte MASK_DELETED = 0b00000001; private final long offset; private final int size; private final int type; diff --git a/src/main/java/org/warp/jcwdb/IndexManager.java b/src/main/java/org/warp/jcwdb/IndexManager.java index 051b6e6..290b0ad 100644 --- a/src/main/java/org/warp/jcwdb/IndexManager.java +++ b/src/main/java/org/warp/jcwdb/IndexManager.java @@ -3,10 +3,11 @@ package org.warp.jcwdb; import java.io.IOException; public interface IndexManager { - public T get(long index, DBReader reader) throws IOException; + T get(long index, DBReader reader) throws IOException; int getType(long index) throws IOException; - public void set(long index, DBDataOutput writer) throws IOException; - public void delete(long index) throws IOException; - public boolean has(long index); - public void close() throws IOException; + long add(DBDataOutput writer) throws IOException; + void set(long index, DBDataOutput writer) throws IOException; + void delete(long index) throws IOException; + boolean has(long index); + void close() throws IOException; } diff --git a/src/main/java/org/warp/jcwdb/JCWDatabase.java b/src/main/java/org/warp/jcwdb/JCWDatabase.java index 90d6beb..810e1d6 100644 --- a/src/main/java/org/warp/jcwdb/JCWDatabase.java +++ b/src/main/java/org/warp/jcwdb/JCWDatabase.java @@ -2,30 +2,64 @@ package org.warp.jcwdb; import java.io.IOException; import java.nio.file.Path; +import java.util.Map; +import java.util.WeakHashMap; -public class JCWDatabase { - private final TypesManager typesManager; - private final MixedIndexDatabase indices; +public class JCWDatabase implements AutoCloseable { + protected final TypesManager typesManager; + protected final MixedIndexDatabase indices; + private final WeakHashMap> references; + private final WeakHashMap> referencesByObject; public JCWDatabase(Path dataFile, Path metadataFile) throws IOException { - this.typesManager = new TypesManager(); + this.typesManager = new TypesManager(this); this.indices = new MixedIndexDatabase(typesManager, dataFile, metadataFile); + this.references = new WeakHashMap<>(); + this.referencesByObject = new WeakHashMap<>(); } - - public EntryReference getRoot() { - // Get type of index 0 - int type = this.indices.getType(0); - // Get the parser - DBTypeParser parser = this.typesManager.get(type); - // Return the reference + + public EntryReference getRoot() throws IOException { try { - return new EntryReference(this, 0, parser); + return get(0); } catch (IOException e) { - throw new RuntimeException("Can't load root!", e); + throw new IOException("Can't load root!", e); } } - public IndexManager getIndexManager() { - return indices; + public EntryReference get(long index) throws IOException { + EntryReference ref = (EntryReference) this.references.getOrDefault(index, null); + if (ref == null) { + int type = this.indices.getType(index); + DBTypeParser typeParser = this.typesManager.get(type); + ref = new EntryReference<>(this, index, typeParser); + this.references.put(index, ref); + this.referencesByObject.put(ref.value, ref); + } + return ref; + } + + public EntryReference add(T o) throws IOException { + EntryReference ref = (EntryReference) referencesByObject.getOrDefault(o, null); + if (ref != null) { + return ref; + } + DBTypeParser typeParser = this.typesManager.get((Class) o.getClass()); + long index = indices.add(typeParser.getWriter(o)); + ref = new EntryReference<>(this, index, typeParser); + this.references.put(index, ref); + this.referencesByObject.put(o, ref); + return ref; + } + + protected void removeEntryReference(long index) { + this.references.remove(index); + } + + @Override + public void close() throws Exception { + for (Map.Entry> reference : references.entrySet()) { + reference.getValue().close(); + } + this.indices.close(); } } diff --git a/src/main/java/org/warp/jcwdb/LightList.java b/src/main/java/org/warp/jcwdb/LightList.java new file mode 100644 index 0000000..3753684 --- /dev/null +++ b/src/main/java/org/warp/jcwdb/LightList.java @@ -0,0 +1,193 @@ +package org.warp.jcwdb; + +import java.io.IOException; +import java.util.*; + +public class LightList implements List { + + public final ArrayList internalList; + private final transient JCWDatabase db; + + public LightList(JCWDatabase db, ArrayList internalList) { + this.internalList = internalList; + this.db = db; + } + + @Override + public int size() { + return internalList.size(); + } + + @Override + public boolean isEmpty() { + return internalList.isEmpty(); + } + + @Override + public boolean contains(Object o) { + if (o != null) { + for (Long element : internalList) { + try { + EntryReference ref = db.get(element); + if (o.equals(ref.value)) { + return true; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return false; + } + + @Override + public Iterator iterator() { + final ArrayList elements = new ArrayList<>(); + for (Long element : internalList) { + try { + elements.add((T) db.get(element).value); + } catch (IOException e) { + e.printStackTrace(); + } + } + return elements.iterator(); + } + + @Override + public T[] toArray() { + final T[] elements = (T[]) new Objects[internalList.size()]; + for (int i = 0; i < elements.length; i++) { + try { + elements[i] = (T) db.get(internalList.get(i)).value; + } catch (IOException e) { + e.printStackTrace(); + } + } + return elements; + } + + @Override + public T1[] toArray(T1[] a) { + final T1[] elements = (T1[]) new Objects[internalList.size()]; + for (int i = 0; i < elements.length; i++) { + try { + elements[i] = (T1) db.get(internalList.get(i)).value; + } catch (IOException e) { + e.printStackTrace(); + } + } + return elements; + } + + @Override + public boolean add(T o) { + EntryReference ref; + try { + ref = db.add(o); + } catch (IOException e) { + throw (NullPointerException) new NullPointerException().initCause(e); + } + return internalList.add(ref.getIndex()); + } + + @Override + public boolean remove(Object o) { + EntryReference ref; + try { + ref = db.add((T) o); + } catch (IOException e) { + throw (NullPointerException) new NullPointerException().initCause(e); + } + return internalList.remove(ref.getIndex()); + } + + @Override + public boolean containsAll(Collection c) { + // TODO: implement + return false; + } + + @Override + public boolean addAll(Collection c) { + // TODO: implement + return false; + } + + @Override + public boolean addAll(int index, Collection c) { + // TODO: implement + return false; + } + + @Override + public boolean removeAll(Collection c) { + // TODO: implement + return false; + } + + @Override + public boolean retainAll(Collection c) { + // TODO: implement + return false; + } + + @Override + public void clear() { + // TODO: implement + + } + + @Override + public T get(int index) { + // TODO: implement + return null; + } + + @Override + public T set(int index, T element) { + // TODO: implement + return null; + } + + @Override + public void add(int index, T element) { + // TODO: implement + + } + + @Override + public T remove(int index) { + // TODO: implement + return null; + } + + @Override + public int indexOf(Object o) { + // TODO: implement + return 0; + } + + @Override + public int lastIndexOf(Object o) { + // TODO: implement + return 0; + } + + @Override + public ListIterator listIterator() { + // TODO: implement + return null; + } + + @Override + public ListIterator listIterator(int index) { + // TODO: implement + return null; + } + + @Override + public List subList(int fromIndex, int toIndex) { + // TODO: implement + return null; + } +} diff --git a/src/main/java/org/warp/jcwdb/MixedIndexDatabase.java b/src/main/java/org/warp/jcwdb/MixedIndexDatabase.java index 1054837..b597120 100644 --- a/src/main/java/org/warp/jcwdb/MixedIndexDatabase.java +++ b/src/main/java/org/warp/jcwdb/MixedIndexDatabase.java @@ -20,30 +20,46 @@ public class MixedIndexDatabase implements IndexManager { } @Override - public T get(long index, DBReader reader) { - // TODO: implement - return null; + public T get(long index, DBReader reader) throws IOException { + if (cacheIndices.has(index)) { + return cacheIndices.get(index, reader); + } else { + return fileIndices.get(index, reader); + } } @Override - public int getType(long index) { - // TODO: implement - return -1; + public int getType(long index) throws IOException { + if (cacheIndices.has(index)) { + return cacheIndices.getType(index); + } else { + return fileIndices.getType(index); + } } @Override - public void set(long index, DBDataOutput writer) { - + public long add(DBDataOutput writer) throws IOException { + return fileIndices.add(writer); } @Override - public void delete(long index) { + public void set(long index, DBDataOutput writer) throws IOException { + if (cacheIndices.has(index)) { + cacheIndices.set(index, writer); + } else { + fileIndices.set(index, writer); + } + } + @Override + public void delete(long index) throws IOException { + cacheIndices.delete(index); + fileIndices.delete(index); } @Override public boolean has(long index) { - return false; + return cacheIndices.has(index) || fileIndices.has(index); } @Override diff --git a/src/main/java/org/warp/jcwdb/TypesManager.java b/src/main/java/org/warp/jcwdb/TypesManager.java index 83688e5..b572be7 100644 --- a/src/main/java/org/warp/jcwdb/TypesManager.java +++ b/src/main/java/org/warp/jcwdb/TypesManager.java @@ -6,17 +6,24 @@ import java.util.HashMap; public class TypesManager { private final Map> types; - - public TypesManager() { + private final Map, DBTypeParser> typesByClass; + + public TypesManager(JCWDatabase db) { types = new HashMap<>(); - DBStandardTypes.registerStandardTypes(this); + typesByClass = new HashMap<>(); + DBStandardTypes.registerStandardTypes(db, this); } - public void registerType(int type, DBTypeParser parser) { + public void registerType(Class clazz, int type, DBTypeParser parser) { this.types.put(type, parser); + this.typesByClass.put(clazz, parser); } - + public DBTypeParser get(int type) { return types.get(type).cast(); } + + public DBTypeParser get(Class type) { + return typesByClass.get(type).cast(); + } }