diff options
author | Mark Spruiell <mes@zeroc.com> | 2009-05-18 14:03:42 -0700 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2009-05-18 14:03:42 -0700 |
commit | b30ccc77d3a9822c6ffcebf9b45945822df200bc (patch) | |
tree | 94105ea42fa81ad0b8731b05a46c7f64304dec55 /java/src/Freeze/MapInternal/IteratorI.java | |
parent | Removed Freeze.UseNonmutating (diff) | |
download | ice-b30ccc77d3a9822c6ffcebf9b45945822df200bc.tar.bz2 ice-b30ccc77d3a9822c6ffcebf9b45945822df200bc.tar.xz ice-b30ccc77d3a9822c6ffcebf9b45945822df200bc.zip |
bug 252 - Freeze finalizers
bug 2552 - Update Freeze for Java5
Diffstat (limited to 'java/src/Freeze/MapInternal/IteratorI.java')
-rw-r--r-- | java/src/Freeze/MapInternal/IteratorI.java | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/java/src/Freeze/MapInternal/IteratorI.java b/java/src/Freeze/MapInternal/IteratorI.java new file mode 100644 index 00000000000..4af39cf7498 --- /dev/null +++ b/java/src/Freeze/MapInternal/IteratorI.java @@ -0,0 +1,422 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Freeze.MapInternal; + +import Freeze.Connection; +import Freeze.ConnectionI; +import Freeze.DatabaseException; +import Freeze.DeadlockException; +import Freeze.NotFoundException; +import Freeze.Map; + +class IteratorI<K, V> implements Freeze.Map.EntryIterator<java.util.Map.Entry<K, V>> +{ + IteratorI(MapI<K, V> map, IteratorModel<K, V> model) + { + _map = map; + _model = model; + _trace = model.traceLevels(); + _dbName = model.dbName(); + + try + { + _txn = _map.connection().dbTxn(); + _cursor = _model.openCursor(); + } + catch(com.sleepycat.db.DeadlockException dx) + { + dead(); + DeadlockException ex = new DeadlockException( + _trace.errorPrefix + "EntryIterator constructor: " + dx.getMessage(), + _map.connection().currentTransaction()); + ex.initCause(dx); + throw ex; + } + catch(com.sleepycat.db.DatabaseException dx) + { + dead(); + DatabaseException ex = new DatabaseException(); + ex.initCause(dx); + ex.message = _trace.errorPrefix + "EntryIterator constructor: " + dx.getMessage(); + throw ex; + } + + _iteratorListToken = _map.addIterator(this); + } + + public boolean + hasNext() + { + if(_current == null || _current == _lastReturned) + { + try + { + if(_current == null) + { + _current = _model.firstEntry(_cursor); + } + else + { + _current = _model.nextEntry(_cursor); + } + } + catch(com.sleepycat.db.DeadlockException dx) + { + dead(); + DeadlockException ex = new DeadlockException( + _trace.errorPrefix + "Dbc.get: " + dx.getMessage(), _map.connection().currentTransaction()); + ex.initCause(dx); + throw ex; + } + catch(com.sleepycat.db.DatabaseException dx) + { + dead(); + DatabaseException ex = new DatabaseException(); + ex.initCause(dx); + ex.message = _trace.errorPrefix + "Dbc.get: " + dx.getMessage(); + throw ex; + } + + // + // For a read-only iterator, we can close the cursor automatically when there + // are no more entries. + // + if(_current == null && _txn == null) + { + close(); + } + + if(_current != null) + { + _current.iterator(this); + } + + return _current != null; + } + else + { + return true; + } + } + + public java.util.Map.Entry<K, V> + next() + { + if(hasNext()) + { + _lastReturned = _current; + return _lastReturned; + } + else + { + throw new java.util.NoSuchElementException(); + } + } + + public void + remove() + { + if(_txn == null) + { + throw new UnsupportedOperationException( + _trace.errorPrefix + "Cannot remove using an iterator without a transaction"); + } + + // + // Remove the last object returned by next() + // + if(_lastReturned == null) + { + throw new IllegalStateException(); + } + + if(_lastReturned == _current) + { + try + { + if(_cursor.delete() == com.sleepycat.db.OperationStatus.KEYEMPTY) + { + throw new IllegalStateException(); + } + } + catch(com.sleepycat.db.DeadlockException e) + { + dead(); + DeadlockException ex = new DeadlockException(_trace.errorPrefix + "Dbc.del: " + e.getMessage(), + _map.connection().currentTransaction()); + ex.initCause(e); + throw ex; + } + catch(com.sleepycat.db.DatabaseException e) + { + DatabaseException ex = new DatabaseException(); + ex.initCause(e); + ex.message = _trace.errorPrefix + "Dbc.del: " + e.getMessage(); + throw ex; + } + } + else + { + // + // Duplicate the cursor and move the _lastReturned element to delete it (using the duplicate). + // + + // + // This works only for non-index iterators. + // + if(_cursor instanceof com.sleepycat.db.SecondaryCursor) + { + throw new UnsupportedOperationException( + _trace.errorPrefix + "Cannot remove using an iterator retrieved through an index"); + } + + com.sleepycat.db.Cursor clone = null; + + try + { + clone = _cursor.dup(true); + + // + // Not interested in data. + // + com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(); + dbValue.setPartial(true); + + com.sleepycat.db.OperationStatus rc = clone.getSearchKey(_lastReturned.getDbKey(), dbValue, null); + + if(rc == com.sleepycat.db.OperationStatus.NOTFOUND) + { + throw new IllegalStateException(); + } + if(clone.delete() == com.sleepycat.db.OperationStatus.KEYEMPTY) + { + throw new IllegalStateException(); + } + } + catch(com.sleepycat.db.DeadlockException e) + { + dead(); + DeadlockException ex = new DeadlockException( + _trace.errorPrefix + "EntryIterator.remove: " + e.getMessage(), + _map.connection().currentTransaction()); + ex.initCause(e); + throw ex; + } + catch(com.sleepycat.db.DatabaseException e) + { + DatabaseException ex = new DatabaseException(); + ex.initCause(e); + ex.message = _trace.errorPrefix + "EntryIterator.remove: " + e.getMessage(); + throw ex; + } + finally + { + if(clone != null) + { + closeCursor(clone); + } + } + } + } + + // + // Extra operations. + // + public void + close() + { + if(_iteratorListToken != null) + { + _map.removeIterator(_iteratorListToken); + _iteratorListToken = null; + } + + if(_cursor != null) + { + com.sleepycat.db.Cursor cursor = _cursor; + _cursor = null; + closeCursor(cursor); + } + } + + // + // An alias for close() + // + public void + destroy() + { + close(); + } + + protected void + finalize() + throws Throwable + { + if(_cursor != null) + { + _trace.logger.warning( + "iterator leaked for Map \"" + _dbName + "\"; the application " + + "should have closed it earlier by calling Map.EntryIterator.close(), " + + "Map.closeAllIterators(), Map.close(), Connection.close(), or (if also " + + "leaking a transaction) Transaction.commit() or Transaction.rollback()"); + } + super.finalize(); + } + + void + setValue(EntryI<K, V> entry, V value) + { + if(_cursor instanceof com.sleepycat.db.SecondaryCursor) + { + throw new UnsupportedOperationException( + _trace.errorPrefix + "Cannot set an iterator retrieved through an index"); + } + + if(_txn == null) + { + throw new UnsupportedOperationException( + _trace.errorPrefix + "Cannot set a value without a transaction"); + } + + // + // Are we trying to update the current value? + // + if(_current == entry) + { + // + // Yes, update it directly + // + byte[] v = _map.encodeValue(value, _map.connection().getCommunicator()); + com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(v); + + try + { + _cursor.putCurrent(dbValue); + } + catch(com.sleepycat.db.DeadlockException e) + { + dead(); + DeadlockException ex = new DeadlockException(_trace.errorPrefix + "Dbc.put: " + e.getMessage(), + _map.connection().currentTransaction()); + ex.initCause(e); + throw ex; + } + catch(com.sleepycat.db.DatabaseException e) + { + DatabaseException ex = new DatabaseException(); + ex.initCause(e); + ex.message = _trace.errorPrefix + "Dbc.put: " + e.getMessage(); + throw ex; + } + } + else + { + // + // Duplicate the cursor and move the entry + // element to update it (using the duplicate cursor) + // + + com.sleepycat.db.Cursor clone = null; + + try + { + clone = _cursor.dup(true); + + // + // Not interested in data + // + com.sleepycat.db.DatabaseEntry dummy = new com.sleepycat.db.DatabaseEntry(); + dummy.setPartial(true); + + com.sleepycat.db.OperationStatus rc = clone.getSearchKey(entry.getDbKey(), dummy, null); + + if(rc == com.sleepycat.db.OperationStatus.NOTFOUND) + { + NotFoundException ex = new NotFoundException(); + ex.message = _trace.errorPrefix + "Dbc.get: DB_NOTFOUND"; + throw ex; + } + + byte[] v = _map.encodeValue(value, _map.connection().getCommunicator()); + com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(v); + clone.putCurrent(dbValue); + } + catch(com.sleepycat.db.DeadlockException e) + { + dead(); + DeadlockException ex = new DeadlockException( + _trace.errorPrefix + "EntryIterator.setValue: " + e.getMessage(), + _map.connection().currentTransaction()); + ex.initCause(e); + throw ex; + } + catch(com.sleepycat.db.DatabaseException e) + { + DatabaseException ex = new DatabaseException(); + ex.initCause(e); + ex.message = _trace.errorPrefix + "EntryIterator.setValue: " + e.getMessage(); + throw ex; + } + finally + { + if(clone != null) + { + closeCursor(clone); + } + } + } + } + + private void + closeCursor(com.sleepycat.db.Cursor cursor) + { + try + { + cursor.close(); + } + catch(com.sleepycat.db.DeadlockException e) + { + dead(); + DeadlockException ex = new DeadlockException( + _trace.errorPrefix + "Dbc.close: " + e.getMessage(), _map.connection().currentTransaction()); + ex.initCause(e); + throw ex; + } + catch(com.sleepycat.db.DatabaseException e) + { + DatabaseException ex = new DatabaseException(); + ex.initCause(e); + ex.message = _trace.errorPrefix + "Dbc.close: " + e.getMessage(); + throw ex; + } + } + + private void + dead() + { + if(_cursor != null) + { + com.sleepycat.db.Cursor cursor = _cursor; + _cursor = null; + closeCursor(cursor); + } + } + + private final MapI<K, V> _map; + private final IteratorModel<K, V> _model; + + private final TraceLevels _trace; + private final String _dbName; // For use in finalizer. + private final com.sleepycat.db.Transaction _txn; + private com.sleepycat.db.Cursor _cursor; + private EntryI<K, V> _current; + private EntryI<K, V> _lastReturned; + private Object _iteratorListToken; +} |