?? recordstore.java
字號:
RecordHeader newrh = null; try { rh = findRecord(recordId, false); // throws InvalidRIDException } catch (java.io.IOException ioe) { throw new RecordStoreException("error finding record data"); } /* * The size of the data and space allocated to the * current record is known here, as is the new size. * Determine if the new data will fit, or if this * record will have to be stored elsewhere. */ if (numBytes <= rh.blockSize - DB_RECORD_HEADER_LENGTH) { /* * The new data should fit within the existing record * location in the file. Store the new data and * patch up the record's header fields. */ int allocSize = getAllocSize(numBytes); if (rh.blockSize - allocSize >= DB_BLOCK_SIZE + DB_RECORD_HEADER_LENGTH) { splitRecord(rh, allocSize); // sets rh.blockSize } rh.dataLenOrNextFree = numBytes; try { rh.store(); // write the new record header recHeadCache.insert(rh); // add to cache if (newData != null) { rh.write(newData, offset); } } catch (java.io.IOException ioe) { throw new RecordStoreException("error writing record" + " data"); } } else { /* * The new data is longer than the old data. It needs to * be relocated to elsewhere within <code>dbfile</code>. * Search the free list to see if there's a space where to * store it. Otherwise append it to the end of the file. */ freeRecord(rh); // calls rh.store() newrh = allocateNewRecordStorage(recordId, numBytes); try { newrh.write(newData, offset); // NOTE: I/O exception leaves space allocated & unused } } catch (java.io.IOException ioe) { throw new RecordStoreException("error moving record " + "data"); } } // update database header info and sync to file dbVersion++; storeDBState(); notifyRecordChangedListeners(recordId); } } /* * Public RecordStore accessor methods */ /** * Returns the name of this RecordStore. Not synchronized as * the name is immutable. * * @return the name of this RecordStore. * * @exception RecordStoreNotOpenException if the record store is closed */ public String getName() throws RecordStoreNotOpenException { checkOpen(); return recordStoreName; } /** * Each time a record store is modified (record added, modified, deleted), * it's <em>version</em> is incremented. This can be used by MIDlets to * quickly tell if anything has been modified. * * The initial version number is implementation dependent. * The increment is a positive integer greater than 0. * The version number only increases as the RecordStore is updated. * * @return the current record store version. * * @exception RecordStoreNotOpenException if the record store is not open. */ public int getVersion() throws RecordStoreNotOpenException { checkOpen(); return dbVersion; } /** * Returns the number of records currently in the record store. * * @return the number of records currently in the record store. * * @exception RecordStoreNotOpenException if the record store is not open. */ public int getNumRecords() throws RecordStoreNotOpenException { checkOpen(); return dbNumLiveRecords; } /** * Returns the amount of space, in bytes, that the record store * occupies. The size returned includes any overhead associated * with the implementation, such as the data structures * used to hold the state of the record store, etc. * * @exception RecordStoreNotOpenException if the record store is * not open. * * @return the size of the record store in bytes. */ public int getSize() throws RecordStoreNotOpenException { checkOpen(); // return the file size of the record store file return dbDataEnd; } /** * Returns the amount of additional room (in bytes) available for * this record store to grow. Note that this is not necessarily * the amount of extra MIDlet-level data which can be stored, * as implementations may store additional data structures with * each record to support integration with native applications, * synchronization, etc. * * @exception RecordStoreNotOpenException if the record store is not open. * * @return the amount of additional room (in bytes) available for * this record store to grow. */ public int getSizeAvailable() throws RecordStoreNotOpenException { checkOpen(); int rv = RecordStoreFile.spaceAvailable() - DB_BLOCK_SIZE - DB_RECORD_HEADER_LENGTH; return (rv < 0) ? 0 : rv; } /** * Returns the last time the record store was modified, in the format * used by System.currentTimeMillis(). * * @return the last time the record store was modified, in the format * used by <code>System.currentTimeMillis()</code>. * * @exception RecordStoreNotOpenException if the record store is not open. */ public long getLastModified() throws RecordStoreNotOpenException { checkOpen(); return dbLastModified; } /** * Adds the specified RecordListener. If the specified listener * is already registered, it will not be added a second time. * When a record store is closed, all listeners are removed. * * @param listener the RecordChangedListener to add. * * @see #removeRecordListener */ public void addRecordListener(RecordListener listener) { synchronized (rsLock) { if (!recordListener.contains(listener)) recordListener.addElement(listener); } } /** * Removes the specified RecordListener. If the specified listener * is not registered, this method does nothing. * * @param listener the RecordChangedListener to remove. * * @see #addRecordListener */ public void removeRecordListener(RecordListener listener) { synchronized (rsLock) { recordListener.removeElement(listener); } } /** * Returns the recordId of the next record to be added to the * record store. This can be useful for setting up pseudo-relational * relationships. That is, if you have two or more * record stores whose records need to refer to one another, you can * predetermine the recordIds of the records that will be created * in one record store, before populating the fields and allocating * the record in another record store. Note that the recordId returned * is only valid while the record store remains open and until a call * to <code>addRecord()</code>. * * @return the record id of the next record to be added to the * record store. * * @exception RecordStoreNotOpenException if the record store is not open. * @exception RecordStoreException if a different record store-related * exception occurred. */ public int getNextRecordID() throws RecordStoreNotOpenException, RecordStoreException { checkOpen(); return dbNextRecordID; } /** * Returns an enumeration for traversing a set of records in the * record store in an optionally specified order.<p> * * The filter, if non-null, will be used to determine what * subset of the record store records will be used.<p> * * The comparator, if non-null, will be used to determine the * order in which the records are returned.<p> * * If both the filter and comparator are null, the enumeration * will traverse all records in the record store in an undefined * order. This is the most efficient way to traverse all of the * records in a record store.<p> * * The first call to <code>RecordEnumeration.nextRecord()</code> * returns the record data from the first record in the sequence. * Subsequent calls to <code>RecordEnumeration.nextRecord()</code> * return the next consecutive record's data. To return the record * data from the previous consecutive from any * given point in the enumeration, call <code>previousRecord()</code>. * On the other hand, if after creation the first call is to * <code>previousRecord()</code>, the record data of the last element * of the enumeration will be returned. Each subsequent call to * <code>previousRecord()</code> will step backwards through the * sequence. * * @param filter if non-null, will be used to determine what * subset of the record store records will be used. * @param comparator if non-null, will be used to determine the * order in which the records are returned. * @param keepUpdated if true, the enumerator will keep its enumeration * current with any changes in the records of the record store. * Use with caution as there are possible performance * consequences. If false the enumeration will not be kept * current and may return recordIds for records that have been * deleted or miss records that are added later. It may also * return records out of order that have been modified after the * enumeration was built. Note that any changes to records in the * record store are accurately reflected when the record is later * retrieved, either directly or through the enumeration. The * thing that is risked by setting this parameter false is the * filtering and sorting order of the enumeration when records * are modified, added, or deleted. * * @exception RecordStoreNotOpenException if the record store is not open. * * @see RecordEnumeration#rebuild * * @return an enumeration for traversing a set of records in the * record store in an optionally specified order. */ public RecordEnumeration enumerateRecords(RecordFilter filter, RecordComparator comparator, boolean keepUpdated) throws RecordStoreNotOpenException { checkOpen(); return new RecordEnumerationImpl(this, filter, comparator, keepUpdated); } /* * Private Memory Management Methods */ /** * Find the record header for a record <code>recordId</code>. * * @param recordId the id of the desired record header. * @param addToCache true if this record should be added to cache * if found. * * @return the record header for the given record, or null if * the record cannot be found. */ private RecordHeader findRecord(int recordId, boolean addToCache) throws InvalidRecordIDException, java.io.IOException { RecordHeader rh; int offset; int cur_offset = dbFirstRecordOffset; // if no records exist, throw an exception if (cur_offset == 0) { throw new InvalidRecordIDException(); } // look for the record in the cache rh = recHeadCache.get(recordId); if (rh != null) { return rh; } /* * requested record header is NOT in cache... * search through the linked list of records * in the file. */ rh = new RecordHeader(); while (cur_offset != 0) { rh.load(cur_offset); if (rh.id == recordId) { break; } else { cur_offset = rh.nextOffset; } } if (cur_offset == 0) { // hit the end of the linked list w/o finding record. throw new InvalidRecordIDException(); } if (addToCache) recHeadCache.insert(rh); return rh; } /** * Return the block allocation size for a record with <code>numBytes * </code> data bytes. This includes space for the record header * and is a multiple of <code>DB_BLOCK_SIZE</code>. * * @param numBytes number of data bytes that will be stored in record * * @return the amount of space to allocate for this record. */ private int getAllocSize(int numBytes) { int rv; int pad; rv = DB_RECORD_HEADER_LENGTH + numBytes; pad = DB_BLOCK_SIZE - (rv % DB_BLOCK_SIZE); if (pad != DB_BLOCK_SIZE) rv += pad; return rv; } /** * Returns a new record header for record <code>id</code> large * enough to hold <code>dataSize</code> bytes of record data. * * Picks a free block using a first fit strategy that is * large enough for a record header and the associated * record data. The block will be a multiple of DB_BLOCK_SIZE. * * @param id the record id to assign to the returned record header. * @param dataSize length of record data that will be * stored with this record.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號