Commit 58bbc2d2 authored by Stephanie Gawroriski's avatar Stephanie Gawroriski
Browse files

Allow record stores to opened and created.

parent 968bda25
......@@ -39,10 +39,11 @@ More detailed changes:
acceleration is used, previously only a subset of methods were
implemented.
* Additions
* `java.util.Vector`, was missing.
* Added basic support for record stores.
* Added proprietary `ExtendedTaskManager` interface which can be used
to specify arguments, system properties, and console output alternatives
to launched tasks.
* `java.util.Vector`, was missing.
* Changes
* Moved the graphics drawing operations to another class.
* Made all the graphics operations not throw a `TODO`, instead they will
......
......@@ -21,7 +21,7 @@ import java.util.Set;
* @since 2018/12/13
*/
public final class TemporaryVinylRecord
extends VinylRecord
implements VinylRecord
{
/** The lock for this record. */
protected final BasicVinylLock lock =
......@@ -35,12 +35,50 @@ public final class TemporaryVinylRecord
private volatile int _nextvid =
1;
/**
* {@inheritDoc}
* @since 2018/12/14
*/
@Override
public final VinylLock lock()
{
return this.lock.lock();
}
/**
* {@inheritDoc}
* @since 2019/04/15
*/
@Override
public final int pageAdd(int __vid, byte[] __b, int __o, int __l,
int __tag)
throws IndexOutOfBoundsException, NullPointerException
{
if (__b == null)
throw new NullPointerException("NARG");
if (__o < 0 || __l < 0 || (__o + __l) > __b.length)
throw new IndexOutOfBoundsException("IOOB");
// Locate the volume
Volume vol = this._volumes.get(__vid);
if (vol == null)
return ERROR_NO_VOLUME;
// Create new page
int pid = vol._nextpid++;
Page page;
vol._pages.put(pid, (page = new Page(pid)));
// Store page data, will return the PID or error
return page.setData(__b, __o, __l, __tag);
}
/**
* {@inheritDoc}
* @since 2019/04/14
*/
@Override
public final int createVolume(long __sid, String __n, boolean __wo)
public final int volumeCreate(long __sid, String __n, boolean __wo)
throws NullPointerException
{
if (__n == null)
......@@ -60,7 +98,7 @@ public final class TemporaryVinylRecord
* @since 2019/04/14
*/
@Override
public final int[] listVolumes()
public final int[] volumeList()
{
Set<Integer> keys = this._volumes.keySet();
......@@ -78,20 +116,20 @@ public final class TemporaryVinylRecord
/**
* {@inheritDoc}
* @since 2018/12/14
* @since 2019/04/14
*/
@Override
public final VinylLock lock()
public final String volumeName(int __vid)
{
return this.lock.lock();
throw new todo.TODO();
}
/**
* {@inheritDoc}
* @since 2019/04/14
* @since 2019/04/15
*/
@Override
public final String volumeName(int __vid)
public final boolean volumeOtherWritable(int __vid)
{
throw new todo.TODO();
}
......@@ -107,7 +145,82 @@ public final class TemporaryVinylRecord
}
/**
* Represents a track in the record.
* Represents a single page.
*
* @since 2019/04/15
*/
public static final class Page
{
/** The page ID. */
protected final int pid;
/** The page data. */
volatile byte[] _data;
/** The tag. */
volatile int _tag;
/**
* Initializes the page.
*
* @param __pid The page ID.
* @since 2019/04/15
*/
public Page(int __pid)
{
// Setup PID
this.pid = __pid;
}
/**
* Sets the page data.
*
* @param __pid The page ID.
* @param __b The data.
* @param __o Offset into data.
* @param __l The length of data.
* @return The page ID or a negative value if an error.
* @throws IndexOutOfBoundsException If the offset and/or length
* exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2019/04/15
*/
public final int setData(byte[] __b, int __o, int __l, int __tag)
throws IndexOutOfBoundsException, NullPointerException
{
if (__b == null)
throw new NullPointerException("NARG");
if (__o < 0 || __l < 0 || (__o + __l) > __b.length)
throw new IndexOutOfBoundsException("IOOB");
// Create copy of the data
try
{
// Allocate and copy data
byte[] place = new byte[__l];
for (int i = __o, o = 0; o < __l; i++, o++)
place[o] = __b[i];
// Store this data
this._data = place;
}
// No memory to store this data?
catch (OutOfMemoryError e)
{
return ERROR_NO_MEMORY;
}
// Set tag
this._tag = __tag;
// Return PID
return this.pid;
}
}
/**
* Represents a single volume.
*
* @since 2019/04/14
*/
......@@ -125,6 +238,14 @@ public final class TemporaryVinylRecord
/** Allow write by others? */
protected final boolean writeother;
/** Pages in this volume. */
final Map<Integer, Page> _pages =
new LinkedHashMap<>();
/** The next page ID. */
volatile int _nextpid =
1;
/**
* Initializes the volume.
*
......
......@@ -17,8 +17,48 @@ package cc.squirreljme.runtime.rms;
*
* @since 2018/12/13
*/
public abstract class VinylRecord
public interface VinylRecord
{
/** No memory is available. */
public static final int ERROR_NO_MEMORY =
-1;
/** No such volume. */
public static final int ERROR_NO_VOLUME =
-2;
/** No such page. */
public static final int ERROR_NO_PAGE =
-3;
/**
* Locks this record so only a single set of actions can be performed on
* them, even for the same thread.
*
* @return The lock used to eventually unlock, to be used with
* try-with-resources.
* @since 2018/12/14
*/
public abstract VinylLock lock();
/**
* Adds a page to the given volume.
*
* @param __vid The volume ID.
* @param __b The data to store.
* @param __o The offset into the array.
* @param __l The length of the array.
* @param __tag The tag to identify the given record with.
* @return The ID of the newly created page.
* @throws IndexOutOfBoundsException If the offset and/or length
* are negative or exceed the array bounds.
* @throws NullPointerException On null arguments.
* @since 2019/04/15
*/
public abstract int pageAdd(int __vid, byte[] __b, int __o, int __l,
int __tag)
throws IndexOutOfBoundsException, NullPointerException;
/**
* Creates a new record.
*
......@@ -28,7 +68,7 @@ public abstract class VinylRecord
* @return The identifier of the suite.
* @since 2019/04/14
*/
public abstract int createVolume(long __sid, String __n, boolean __wo);
public abstract int volumeCreate(long __sid, String __n, boolean __wo);
/**
* Returns the list of all available stores.
......@@ -36,17 +76,7 @@ public abstract class VinylRecord
* @return The list of available stores.
* @since 2019/04/14
*/
public abstract int[] listVolumes();
/**
* Locks this record so only a single set of actions can be performed on
* them, even for the same thread.
*
* @return The lock used to eventually unlock, to be used with
* try-with-resources.
* @since 2018/12/14
*/
public abstract VinylLock lock();
public abstract int[] volumeList();
/**
* Returns the name of the given record.
......@@ -65,5 +95,14 @@ public abstract class VinylRecord
* @since 2019/04/14
*/
public abstract long volumeSuiteIdentifier(int __vid);
/**
* Returns if this volume is other writable.
*
* @param __vid The volume ID.
* @return If it is writable by others.
* @since 2019/04/15
*/
public abstract boolean volumeOtherWritable(int __vid);
}
......@@ -20,8 +20,12 @@ import cc.squirreljme.runtime.rms.TemporaryVinylRecord;
import cc.squirreljme.runtime.swm.SuiteName;
import cc.squirreljme.runtime.swm.SuiteVendor;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.microedition.midlet.MIDlet;
import net.multiphasicapps.collections.IdentityLinkedHashSet;
/**
* This is a record store which may be used by an application to store
......@@ -53,6 +57,14 @@ public class RecordStore
/** The vinyl record where everything is stored. */
static final VinylRecord _VINYL;
/** Existing record stores. */
static final Map<Integer, RecordStore> _STORE_CACHE =
new LinkedHashMap<>();
/** Identity map for listeners */
private final Set<RecordListener> _listeners =
new IdentityLinkedHashSet<>();
/** The volume ID. */
private final int _vid;
......@@ -62,6 +74,9 @@ public class RecordStore
/** Write to this? */
private final boolean _write;
/** How many times has this been opened? */
private volatile int _opens;
/**
* Initializes the record store manager.
*
......@@ -110,6 +125,7 @@ public class RecordStore
this._vid = __vid;
this._name = __name;
this._write = __w;
this._opens = 1;
}
/**
......@@ -144,12 +160,33 @@ public class RecordStore
if (!this._write)
throw new RecordStoreException("DC04");
// Used for later
int rv;
RecordListener[] listeners = this.__listeners();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
{
throw new todo.TODO();
// Check open
this.__checkOpen();
// {@squirreljme.error DC06 Could not add the record, there might
// not be enough free space available.}
rv = vinyl.pageAdd(this._vid, __b, __o, __l, __tag);
if (rv == VinylRecord.ERROR_NO_MEMORY)
throw new RecordStoreFullException("DC06");
// {@squirreljme.error DC07 Could not add the record due to an
// error. (The error)}
else if (rv < 0)
throw new RecordStoreException("DC07 " + rv);
}
// Report to the listeners
for (RecordListener l : listeners)
l.recordAdded(this, rv);
return rv;
}
/**
......@@ -186,7 +223,16 @@ public class RecordStore
*/
public void addRecordListener(RecordListener __l)
{
throw new todo.TODO();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
{
// No effect if closed
if (this._opens <= 0)
return;
throw new todo.TODO();
}
}
/**
......@@ -215,7 +261,18 @@ public class RecordStore
public void closeRecordStore()
throws RecordStoreNotOpenException, RecordStoreException
{
throw new todo.TODO();
// Lock the record, so that only a single thread is messing with the
// open counts and such
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
{
// Check open
this.__checkOpen();
// If closed then remove all the listeners
if ((--this._opens) <= 0)
this._listeners.clear();
}
}
/**
......@@ -232,6 +289,9 @@ public class RecordStore
throws InvalidRecordIDException, RecordStoreNotOpenException,
RecordStoreException, SecurityException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -262,6 +322,9 @@ public class RecordStore
RecordComparator __c, boolean __ku, int[] __tags)
throws RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -284,7 +347,7 @@ public class RecordStore
RecordComparator __c, boolean __ku)
throws RecordStoreNotOpenException
{
return enumerateRecords(__f, __c, __ku, null);
return this.enumerateRecords(__f, __c, __ku, null);
}
/**
......@@ -297,6 +360,9 @@ public class RecordStore
public long getLastModified()
throws RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -315,6 +381,9 @@ public class RecordStore
public String getName()
throws RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
return this._name;
}
......@@ -334,6 +403,9 @@ public class RecordStore
public int getNextRecordID()
throws RecordStoreException, RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -358,6 +430,9 @@ public class RecordStore
throws InvalidRecordIDException, RecordStoreException,
RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -388,6 +463,9 @@ public class RecordStore
NullPointerException, RecordStoreException,
RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -411,6 +489,9 @@ public class RecordStore
throws InvalidRecordIDException, RecordStoreException,
RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -429,6 +510,9 @@ public class RecordStore
public RecordStoreInfo getRecordStoreInfo()
throws RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -483,6 +567,9 @@ public class RecordStore
throws InvalidRecordIDException, RecordStoreException,
RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -502,6 +589,9 @@ public class RecordStore
public int getVersion()
throws RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -576,6 +666,9 @@ public class RecordStore
NullPointerException, RecordStoreException,
RecordStoreFullException, RecordStoreNotOpenException
{
// Check open
this.__checkOpen();
// Lock
VinylRecord vinyl = _VINYL;
try (VinylLock lock = vinyl.lock())
......@@ -607,6 +700,33 @@ public class RecordStore
this.setRecord(__id, __b, __o, __l, this.getTag(__id));
}
/**
* Checks that this record store is open.
*
* @throws RecordStoreNotOpenException If it is not open.
* @since 2019/04/15
*/
private final void __checkOpen()
throws RecordStoreNotOpenException
{
// {@squirreljme.error DC05 This record store is not open.
if (this._opens <= 0)
throw new RecordStoreNotOpenException("DC05");
}
/**
* Returns all of the listeners for this record store.
*
* @return The listeners.
* @since 2019/04/15
*/
private final RecordListener[] __listeners()
{
Set<RecordListener> listeners = this._listeners;
return listeners.<RecordListener>toArray(
new RecordListener[listeners.size()]);
}
/**
* Deletes the specified record store.
*
......@@ -653,7 +773,7 @@ public class RecordStore
List<String> rv = new ArrayList<>();
// Go through all IDs and locate record store info
for (int rid : vinyl.listVolumes())
for (int rid : vinyl.volumeList())
{
// Do not add records which belong to another suite
if (mysid != vinyl.volumeSuiteIdentifier(rid))
......@@ -886,7 +1006,7 @@ public class RecordStore
{
// Go through all records and try to find a pre-existing one
int rv = -1;
for (int rid : vinyl.listVolumes())
for (int rid : vinyl.volumeList())
{
// Belongs to another suite?
if (sid != vinyl.volumeSuiteIdentifier(rid))
......@@ -902,7 +1022,18 @@ public class RecordStore
// Open a record which already exists
if (rv >= 0)
throw new todo.TODO();
{
// Use a pre-cached store
Map<Integer, RecordStore> cache = _STORE_CACHE;
RecordStore rs = cache.get(rv);
if (rs == null)
cache.put(rv, (rs = new RecordStore(rv, __name,
sid == mysid || vinyl.volumeOtherWritable(rv))));
// Increment the open count
rs._opens++;
return rs;
}
// {@squirreljme.error DC02 Could not find the specified record
// store. (The name; The vendor; The suite)}
......@@ -912,7 +1043,7 @@ public class RecordStore
// {@squirreljme.error DC03 Could not create the record, it is
// likely that there is not enough space remaining.}
rv = vinyl.createVolume(sid, __name, __write);
rv = vinyl.volumeCreate(sid, __name, __write);
if (rv < 0)
throw new RecordStoreFullException("DC03");
......