diff options
author | Bernard Normier <bernard@zeroc.com> | 2003-08-27 20:49:28 +0000 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2003-08-27 20:49:28 +0000 |
commit | 96562f821fd2ba5e5ed1eb3ec6991e60c1402f06 (patch) | |
tree | 4a8b677c8c89a6c5f89cb83f320e0f0a8343cf4f /java/src | |
parent | Added per-proxy contexts to icej. For ice, added context to operator== and (diff) | |
download | ice-96562f821fd2ba5e5ed1eb3ec6991e60c1402f06.tar.bz2 ice-96562f821fd2ba5e5ed1eb3ec6991e60c1402f06.tar.xz ice-96562f821fd2ba5e5ed1eb3ec6991e60c1402f06.zip |
Freeze Evictor facet changes
Diffstat (limited to 'java/src')
-rw-r--r-- | java/src/Freeze/EvictorI.java | 1541 | ||||
-rw-r--r-- | java/src/Freeze/EvictorIteratorI.java | 53 | ||||
-rw-r--r-- | java/src/Ice/Object.java | 2 | ||||
-rw-r--r-- | java/src/Ice/ObjectImpl.java | 42 | ||||
-rw-r--r-- | java/src/Ice/PropertiesI.java | 3 | ||||
-rw-r--r-- | java/src/IceXML/StreamI.java | 9 |
6 files changed, 1208 insertions, 442 deletions
diff --git a/java/src/Freeze/EvictorI.java b/java/src/Freeze/EvictorI.java index caa425f68c0..95794af1a96 100644 --- a/java/src/Freeze/EvictorI.java +++ b/java/src/Freeze/EvictorI.java @@ -94,13 +94,12 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable saveNowNoSync(); } - synchronized public void + public void createObject(Ice.Identity ident, Ice.Object servant) { - if(_deactivated) - { - throw new EvictorDeactivatedException(); - } + EvictorElement loadedElement = null; + int loadedElementGeneration = 0; + boolean triedToLoadElement = false; // // Make a copy of ident in case the user later changes it @@ -109,220 +108,477 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable Ice.Identity identCopy = new Ice.Identity(); identCopy.name = ident.name; identCopy.category = ident.category; - - EvictorElement element = (EvictorElement)_evictorMap.get(ident); - if(element != null) - { - synchronized(element) + + for(;;) + { + synchronized(this) { - switch(element.status) + if(_deactivated) { - case clean: + throw new EvictorDeactivatedException(); + } + + EvictorElement element = (EvictorElement)_evictorMap.get(ident); + + if(element == null && triedToLoadElement) + { + if(loadedElementGeneration == _generation) + { + if(loadedElement != null) + { + element = insertElement(null, identCopy, loadedElement); + } + } + else { - element.status = modified; - addToModifiedQueue(identCopy, element); - break; + loadedElement = null; + triedToLoadElement = false; } - case created: - case modified: + } + + boolean replacing = (element != null); + + if(replacing || triedToLoadElement) + { + if(replacing) { // - // Nothing to do. - // No need to push it on the modified queue as a created resp - // modified element is either already on the queue or about - // to be saved. When saved, it becomes clean. + // Destroy all existing facets // - break; - } - case destroyed: + + java.util.Iterator p = element.facets.entrySet().iterator(); + + while(p.hasNext()) + { + java.util.Map.Entry entry = (java.util.Map.Entry) p.next(); + + destroyFacetImpl((Facet) entry.getValue()); + } + } + else { - element.status = modified; // - // No need to push it on the modified queue, as a destroyed element - // is either already on the queue or about to be saved. When saved, - // it becomes dead. + // Let's insert an empty EvictorElement // - break; + element = new EvictorElement(); + _evictorMap.put(identCopy, element); + _evictorList.addFirst(identCopy); + element.identity = identCopy; + element.position = _evictorList.iterator(); + element.position.next(); } - case dead: + + // + // Add all the new facets (recursively) + // + addFacetImpl(element, servant, new String[0], replacing); + + // + // Evict as many elements as necessary + // + evict(); + break; // for(;;) + } + else + { + loadedElementGeneration = _generation; + } + } + + // + // Try to load element and try again + // + assert(loadedElement == null); + assert(triedToLoadElement == false); + loadedElement = load(ident); + triedToLoadElement = true; + } + + if(_trace >= 1) + { + _communicator.getLogger().trace("Freeze::Evictor", + "created \"" + Ice.Util.identityToString(ident) + "\""); + } + } + + public void + addFacet(Ice.Identity ident, String[] facetPath, Ice.Object servant) + { + if(facetPath.length == 0) + { + throw new EmptyFacetPathException(); + } + + EvictorElement loadedElement = null; + int loadedElementGeneration = 0; + + // + // Make a copy of ident in case the user later changes it + // (used when inserting into list or map) + // + Ice.Identity identCopy = new Ice.Identity(); + identCopy.name = ident.name; + identCopy.category = ident.category; + + for(;;) + { + synchronized(this) + { + if(_deactivated) + { + throw new EvictorDeactivatedException(); + } + + EvictorElement element = (EvictorElement)_evictorMap.get(ident); + + if(element == null && loadedElement != null) + { + if(loadedElementGeneration == _generation) { - element.status = created; - addToModifiedQueue(identCopy, element); - break; + element = insertElement(null, identCopy, loadedElement); } - default: + else { - assert(false); - break; + // + // Discard loadedElement + // + loadedElement = null; } } - element.rec.servant = servant; + + if(element != null) + { + String[] parentPath = new String[facetPath.length - 1]; + System.arraycopy(facetPath, 0, parentPath, 0, facetPath.length - 1); + + Facet facet = (Facet) element.facets.get(new StringArray(parentPath)); + if(facet == null) + { + throw new Ice.FacetNotExistException(); + } + + synchronized(facet) + { + if(facet.status == dead || facet.status == destroyed) + { + throw new Ice.FacetNotExistException(); + } + + // + // Throws AlreadyRegisterException if the facet is already registered + // + facet.rec.servant.ice_addFacet(servant, facetPath[facetPath.length - 1]); + } + + // + // We may need to replace (nested) dead or destroyed facets + // + addFacetImpl(element, servant, facetPath, true); + evict(); + break; // for(;;) + } + + loadedElementGeneration = _generation; } - element.position.remove(); - _evictorList.addFirst(identCopy); - element.position = _evictorList.iterator(); - } - else - { - // - // Create a new object - // - - ObjectRecord rec = new ObjectRecord(); - rec.servant = servant; - rec.stats = new Statistics(); - rec.stats.creationTime = System.currentTimeMillis(); - rec.stats.lastSaveTime = 0; - rec.stats.avgSaveTime = 0; - - // - // Add an Ice object with its servant to the evictor queue. - // - element = new EvictorElement(); - element.rec = rec; - element.usageCount = 0; - element.status = created; - - _evictorMap.put(identCopy, element); - _evictorList.addFirst(identCopy); - - element.position = _evictorList.iterator(); - // - // Position the iterator "on" the element. - // - element.position.next(); - - addToModifiedQueue(identCopy, element); + assert(loadedElement == null); // - // Evict as many elements as necessary. + // Load object and loop // - evict(); + loadedElement = load(ident); + if(loadedElement == null) + { + throw new Ice.ObjectNotExistException(); + } } - + if(_trace >= 1) { _communicator.getLogger().trace("Freeze::Evictor", - "created \"" + Ice.Util.identityToString(ident) + "\""); + "added facet to \"" + Ice.Util.identityToString(ident) + "\""); } } - synchronized public void + public void destroyObject(Ice.Identity ident) { - if(_deactivated) - { - throw new EvictorDeactivatedException(); - } + EvictorElement loadedElement = null; + int loadedElementGeneration = 0; + boolean triedToLoadElement = false; + + // + // Make a copy of ident in case the user later changes it + // (used when inserting into list or map) + // + Ice.Identity identCopy = new Ice.Identity(); + identCopy.name = ident.name; + identCopy.category = ident.category; - EvictorElement element = (EvictorElement)_evictorMap.get(ident); - if(element != null) + for(;;) { - synchronized(element) + synchronized(this) { - switch(element.status) + if(_deactivated) + { + throw new EvictorDeactivatedException(); + } + + EvictorElement element = (EvictorElement)_evictorMap.get(ident); + + if(element == null && triedToLoadElement) { - case clean: + if(loadedElementGeneration == _generation) + { + if(loadedElement != null) + { + element = insertElement(null, identCopy, loadedElement); + } + } + else { - element.status = destroyed; + loadedElement = null; + triedToLoadElement = false; + } + } + + boolean destroying = (element != null); + if(destroying || triedToLoadElement) + { + if(destroying) + { // - // Make a copy of ident in case the user later changes it - // (used when inserting into list or map) + // Destroy all existing facets // - Ice.Identity identCopy = new Ice.Identity(); - identCopy.name = ident.name; - identCopy.category = ident.category; - addToModifiedQueue(identCopy, element); - break; + java.util.Iterator p = element.facets.entrySet().iterator(); + + while(p.hasNext()) + { + java.util.Map.Entry entry = (java.util.Map.Entry) p.next(); + + destroyFacetImpl((Facet) entry.getValue()); + } } - case created: + + // + // Evict as many elements as necessary + // + evict(); + break; // for(;;) + } + else + { + loadedElementGeneration = _generation; + } + } + + // + // Try to load element and try again + // + assert(loadedElement == null); + assert(triedToLoadElement == false); + loadedElement = load(ident); + triedToLoadElement = true; + } + + if(_trace >= 1) + { + _communicator.getLogger().trace("Freeze::Evictor", + "destroyed \"" + Ice.Util.identityToString(ident) + "\""); + } + + } + + public void + removeFacet(Ice.Identity ident, String facetPath[]) + { + if(facetPath.length == 0) + { + throw new EmptyFacetPathException(); + } + + EvictorElement loadedElement = null; + int loadedElementGeneration = 0; + + // + // Make a copy of ident in case the user later changes it + // (used when inserting into list or map) + // + Ice.Identity identCopy = new Ice.Identity(); + identCopy.name = ident.name; + identCopy.category = ident.category; + + for(;;) + { + synchronized(this) + { + if(_deactivated) + { + throw new EvictorDeactivatedException(); + } + + EvictorElement element = (EvictorElement)_evictorMap.get(ident); + + if(element == null && loadedElement != null) + { + if(loadedElementGeneration == _generation) { - element.status = dead; - break; + element = insertElement(null, identCopy, loadedElement); } - case modified: + else { - element.status = destroyed; // - // Not necessary to push it on the modified queue, as a modified - // element is either on the queue already or about to be saved - // (at which point it becomes clean) + // Discard loadedElement // - break; + loadedElement = null; } - case destroyed: - case dead: + } + + if(element != null) + { + String[] parentPath = new String[facetPath.length - 1]; + System.arraycopy(facetPath, 0, parentPath, 0, facetPath.length - 1); + + Facet facet = (Facet) element.facets.get(new StringArray(parentPath)); + if(facet == null) { - // - // Nothing to do! - // - break; + throw new Ice.FacetNotExistException(); } - default: + + synchronized(facet) { - assert(false); - break; + if(facet.status == dead || facet.status == destroyed) + { + throw new Ice.FacetNotExistException(); + } + + // + // Throws NotRegisteredException if the facet is not registered + // + facet.rec.servant.ice_removeFacet(facetPath[facetPath.length - 1]); } + removeFacetImpl(element.facets, facetPath); + evict(); + break; // for(;;) } + + loadedElementGeneration = _generation; } - } - else - { - // - // Set a real ObjectRecord in case this object gets recreated - // - - ObjectRecord rec = new ObjectRecord(); - rec.servant = null; - rec.stats = new Statistics(); - rec.stats.creationTime = System.currentTimeMillis(); - rec.stats.lastSaveTime = 0; - rec.stats.avgSaveTime = 0; - // - // Add an Ice object with its servant to the evictor queue. - // - element = new EvictorElement(); - element.rec = rec; - element.usageCount = 0; - element.status = destroyed; - - - // - // Make a copy of ident in case the user later changes it - // (used when inserting into list or map) - // - Ice.Identity identCopy = new Ice.Identity(); - identCopy.name = ident.name; - identCopy.category = ident.category; - - _evictorMap.put(identCopy, element); - _evictorList.addFirst(identCopy); + assert(loadedElement == null); - element.position = _evictorList.iterator(); // - // Position the iterator "on" the element. + // Load object and loop // - element.position.next(); - - addToModifiedQueue(identCopy, element); + loadedElement = load(ident); + if(loadedElement == null) + { + throw new Ice.ObjectNotExistException(); + } + } + + if(_trace >= 1) + { + _communicator.getLogger().trace("Freeze::Evictor", + "removed facet from \"" + Ice.Util.identityToString(ident) + "\""); + } + } + + public void + removeAllFacets(Ice.Identity ident) + { + + EvictorElement loadedElement = null; + int loadedElementGeneration = 0; + + // + // Make a copy of ident in case the user later changes it + // (used when inserting into list or map) + // + Ice.Identity identCopy = new Ice.Identity(); + identCopy.name = ident.name; + identCopy.category = ident.category; + + for(;;) + { + synchronized(this) + { + if(_deactivated) + { + throw new EvictorDeactivatedException(); + } + + EvictorElement element = (EvictorElement)_evictorMap.get(ident); + + if(element == null && loadedElement != null) + { + if(loadedElementGeneration == _generation) + { + element = insertElement(null, identCopy, loadedElement); + } + else + { + // + // Discard loadedElement + // + loadedElement = null; + } + } + + if(element != null) + { + Facet facet = element.mainObject; + synchronized(facet) + { + if(facet.status == dead || facet.status == destroyed) + { + throw new Ice.ObjectNotExistException(); + } + facet.rec.servant.ice_removeAllFacets(); + } + + // + // Destroy all facets except main object + // + java.util.Iterator p = element.facets.entrySet().iterator(); + + while(p.hasNext()) + { + java.util.Map.Entry entry = (java.util.Map.Entry) p.next(); + if(entry.getValue() != element.mainObject) + { + destroyFacetImpl((Facet) entry.getValue()); + } + } + + evict(); + break; // for(;;) + } + + loadedElementGeneration = _generation; + } + + assert(loadedElement == null); // - // Evict as many elements as necessary. + // Load object and loop // - evict(); + loadedElement = load(ident); + if(loadedElement == null) + { + throw new Ice.ObjectNotExistException(); + } } - + if(_trace >= 1) { - _communicator.getLogger().trace("Freeze::Evictor", "destroyed \"" + - Ice.Util.identityToString(ident) + "\""); + _communicator.getLogger().trace("Freeze::Evictor", + "removed all facets from \"" + Ice.Util.identityToString(ident) + "\""); } } - + synchronized public void installServantInitializer(ServantInitializer initializer) { @@ -349,7 +605,7 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable return new EvictorIteratorI(_db, _communicator, _errorPrefix); } - synchronized public boolean + public boolean hasObject(Ice.Identity ident) { synchronized(this) @@ -362,9 +618,9 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable EvictorElement element = (EvictorElement)_evictorMap.get(ident); if(element != null) { - synchronized(element) + synchronized(element.mainObject) { - return (element.status != destroyed && element.status != dead); + return (element.mainObject.status != destroyed && element.mainObject.status != dead); } } } @@ -375,18 +631,22 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable public Ice.Object locate(Ice.Current current, Ice.LocalObjectHolder cookie) { + EvictorElement loadedElement = null; + int loadedElementGeneration = 0; + cookie.value = null; + // // Need to copy current.id, as Ice caches and reuses it // Ice.Identity ident = new Ice.Identity(); ident.name = current.id.name; ident.category = current.id.category; - - ObjectRecord rec = null; for(;;) { EvictorElement element; + boolean objectFound = false; + boolean newObject = false; synchronized(this) { @@ -398,75 +658,64 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable element = (EvictorElement)_evictorMap.get(ident); - if(element != null) + if(element == null && loadedElement != null) + { + if(loadedElementGeneration == _generation) + { + element = insertElement(null, ident, loadedElement); + newObject = true; + } + else + { + // + // Discard loadedElement + // + loadedElement = null; + } + } + + objectFound = (element != null); + + if(objectFound) { // // Ice object found in evictor map. Push it to the front of // the evictor list, so that it will be evicted last. // - element.position.remove(); - _evictorList.addFirst(ident); - element.position = _evictorList.iterator(); - // - // Position the iterator "on" the element. - // - element.position.next(); + if(!newObject) + { + element.position.remove(); + _evictorList.addFirst(ident); + element.position = _evictorList.iterator(); + // + // Position the iterator "on" the element. + // + element.position.next(); + } element.usageCount++; - cookie.value = (Ice.LocalObject)element; + + assert(current.facet != null); + Facet facet = (Facet) element.facets.get(new StringArray(current.facet)); + if(facet != null) + { + cookie.value = facet; + } + evict(); + // // Later (after releasing the mutex), check that this // object is not dead or destroyed // } - else if(rec != null) + else { - // - // Proceed with the object loaded in the previous loop - // - - // - // If an initializer is installed, call it now. - // - if(_initializer != null) - { - _initializer.initialize(current.adapter, ident, rec.servant); - } - - // - // Add an Ice object with its servant to the evictor queue. - // - - element = new EvictorElement(); - element.rec = rec; - element.usageCount = 1; - element.status = clean; - - _evictorMap.put(ident, element); - _evictorList.addFirst(ident); - - element.position = _evictorList.iterator(); - // - // Position the iterator "on" the element. - // - element.position.next(); - - cookie.value = (Ice.LocalObject)element; - - // - // Evict as many elements as necessary. - // - evict(); - - return rec.servant; + loadedElementGeneration = _generation; } - // - // Else fall to the after-sync processing - // } - - if(element != null) + + if(objectFound) { if(_trace >= 2) { @@ -475,14 +724,37 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable "\" in the queue"); } - // - // Return servant if object not dead or destroyed - // - synchronized(element) + if(cookie.value == null) + { + Ice.Object result = null; + synchronized(element.mainObject) + { + if(element.mainObject.status != destroyed && element.mainObject.status != dead) + { + result = element.mainObject.rec.servant; + } + + } + if(_trace >= 2) + { + _communicator.getLogger().trace("Freeze::Evictor", + " \"" + Ice.Util.identityToString(ident) + + "\" does not have the desired facet"); + } + synchronized(this) + { + element.usageCount--; + return result; + } + } + else { - if(element.status != destroyed && element.status != dead) + synchronized(element.mainObject) { - return element.rec.servant; + if(element.mainObject.status != destroyed && element.mainObject.status != dead) + { + return element.mainObject.rec.servant; + } } } @@ -515,9 +787,9 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable + "loading \"" + Ice.Util.identityToString(ident) + "\" from the database"); } - rec = getObject(ident); - - if(rec == null) + loadedElement = load(ident); + + if(loadedElement == null) { // // The Ice object with the given identity does not exist, @@ -525,64 +797,66 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable // return null; } - // - // Else loop - // } } } - public void finished(Ice.Current current, Ice.Object servant, Ice.LocalObject cookie) { assert(servant != null); - EvictorElement element = (EvictorElement)cookie; - boolean enqueue = false; - - if(current.mode != Ice.OperationMode.Nonmutating) + if(cookie != null) { - synchronized(element) + + Facet facet= (Facet)cookie; + assert(facet != null); + + boolean enqueue = false; + + if(current.mode != Ice.OperationMode.Nonmutating) { - if(element.status == clean) + synchronized(facet) { - // - // Assume this operation updated the object - // - element.status = modified; - enqueue = true; + if(facet.status == clean) + { + // + // Assume this operation updated the object + // + facet.status = modified; + enqueue = true; + } } } - } - synchronized(this) - { - assert(!_deactivated); - - // - // Decrease the usage count of the evictor queue element. - // - assert(element.usageCount >= 1); - element.usageCount--; - - if(enqueue) + synchronized(this) { - // - // Need to copy current.id, as Ice caches and reuses it - // - Ice.Identity ident = new Ice.Identity(); - ident.name = current.id.name; - ident.category = current.id.category; + assert(!_deactivated); - addToModifiedQueue(ident, element); - } - else - { // - // Evict as many elements as necessary. + // Decrease the usage count of the evictor queue element. // - evict(); + assert(facet.element.usageCount >= 1); + facet.element.usageCount--; + + if(enqueue) + { + // + // Need to copy current.id, as Ice caches and reuses it + // + Ice.Identity ident = new Ice.Identity(); + ident.name = current.id.name; + ident.category = current.id.category; + + addToModifiedQueue(facet); + } + else + { + // + // Evict as many elements as necessary. + // + evict(); + } } } } @@ -649,7 +923,8 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable _dbEnvHolder.close(); _dbEnvHolder = null; } - _dbEnv = null; + _dbEnv = null; + _initializer = null; } } @@ -719,13 +994,7 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable } int size = allObjects.size(); - - // - // Usage count release - // - java.util.List releaseAfterStreaming = new java.util.ArrayList(); - java.util.List releaseAfterCommit = new java.util.ArrayList(); - + java.util.List streamedObjectQueue = new java.util.ArrayList(); long saveStart = System.currentTimeMillis(); @@ -735,33 +1004,26 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable // for(int i = 0; i < size; i++) { - EvictorElement element = (EvictorElement)_evictorMap.get((Ice.Identity)allObjects.get(i)); + Facet facet = (Facet) allObjects.get(i); - synchronized(element) + synchronized(facet) { - ObjectRecord rec = element.rec; + ObjectRecord rec = facet.rec; boolean streamIt = true; - byte status = element.status; + byte status = facet.status; switch(status) { case created: - { - element.status = clean; - releaseAfterCommit.add(element); - break; - } case modified: { - element.status = clean; - releaseAfterStreaming.add(element); + facet.status = clean; break; - } + } case destroyed: { - element.status = dead; - releaseAfterCommit.add(element); + facet.status = dead; break; } default: @@ -770,7 +1032,6 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable // Nothing to do (could be a duplicate) // streamIt = false; - releaseAfterStreaming.add(element); break; } } @@ -781,13 +1042,15 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable StreamedObject obj = new StreamedObject(); streamedObjectQueue.add(obj); - obj.key = IdentityObjectRecordDict.encodeKeyImpl(allObjects.get(i), _communicator); + EvictorStorageKey esk = new EvictorStorageKey(); + esk.identity = facet.element.identity; + esk.facet = facet.path; + obj.key = marshal(esk, _communicator); obj.status = status; if(status != destroyed) { synchronized(rec.servant) { - obj.value = writeObjectRecordToValue(saveStart, rec); } } @@ -795,21 +1058,6 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable } } - allObjects.clear(); - - if(releaseAfterStreaming.size() > 0) - { - synchronized(this) - { - for(int i = 0; i < releaseAfterStreaming.size(); i++) - { - EvictorElement element = (EvictorElement)releaseAfterStreaming.get(i); - element.usageCount--; - } - } - releaseAfterStreaming.clear(); - } - // // Now let's save all these streamed objects to disk using a transaction // @@ -841,39 +1089,37 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable { StreamedObject obj = (StreamedObject) streamedObjectQueue.get(i); - if(obj.status == destroyed) + switch(obj.status) { - // - // May not exist in the database - // - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(obj.key); - - int err = _db.del(tx, dbKey, 0); - if(err != 0 && err != com.sleepycat.db.Db.DB_NOTFOUND) + case created: + case modified: { - // - // Bug in Freeze - // - throw new DBException(); - } - } - else - { - // - // We can't use NOOVERWRITE as some 'created' objects may - // actually be already in the database - // - - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(obj.key); - com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(obj.value); - - int err = _db.put(tx, dbKey, dbValue, 0); - if(err != 0) + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(obj.key); + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(obj.value); + + int flags = (obj.status == created) ? com.sleepycat.db.Db.DB_NOOVERWRITE : 0; + + int err = _db.put(tx, dbKey, dbValue, flags); + if(err != 0) + { + throw new DBException(); + } + break; + } + case destroyed: { - // - // Bug in Freeze - // - throw new DBException(); + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(obj.key); + + int err = _db.del(tx, dbKey, 0); + if(err != 0) + { + throw new DBException(); + } + break; + } + default: + { + assert(false); } } } @@ -917,14 +1163,16 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable synchronized(this) { + _generation++; - for(int i = 0; i < releaseAfterCommit.size(); i++) + for(int i = 0; i < allObjects.size(); i++) { - EvictorElement element = (EvictorElement)releaseAfterCommit.get(i); - element.usageCount--; + Facet facet = (Facet) allObjects.get(i); + facet.element.usageCount--; } - releaseAfterCommit.clear(); - + allObjects.clear(); + evict(); + if(saveNowThreadsSize > 0) { for(int i = 0; i < saveNowThreadsSize; i++) @@ -939,6 +1187,110 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable } } + + static byte[] + marshalRoot(EvictorStorageKey v, Ice.Communicator communicator) + { + try + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + Ice.Stream __os = new IceXML.StreamI(communicator, pw); + v.ice_marshal("Key", __os); + String str = sw.toString(); + + // + // TODO: fix this! + // + int index = str.indexOf("</identity>"); + String root = str.substring(0, index + 11); + return root.getBytes("UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + Ice.SyscallException e = new Ice.SyscallException(); + e.initCause(ex); + throw e; + } + } + + static byte[] + marshal(EvictorStorageKey v, Ice.Communicator communicator) + { + try + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + Ice.Stream __os = new IceXML.StreamI(communicator, pw); + v.ice_marshal("Key", __os); + return sw.toString().getBytes("UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + Ice.SyscallException e = new Ice.SyscallException(); + e.initCause(ex); + throw e; + } + } + + static EvictorStorageKey + unmarshalKey(byte[] b, Ice.Communicator communicator) + { + try + { + final String data = _header + new String(b, "UTF8") + _footer; + Ice.Stream __is = new IceXML.StreamI(communicator, new java.io.StringReader(data)); + Freeze.EvictorStorageKey __r = new Freeze.EvictorStorageKey(); + __r.ice_unmarshal("Key", __is); + return __r; + } + catch(java.io.UnsupportedEncodingException ex) + { + Ice.SyscallException e = new Ice.SyscallException(); + e.initCause(ex); + throw e; + } + } + + static byte[] + marshal(ObjectRecord v, Ice.Communicator communicator) + { + try + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + Ice.Stream __os = new IceXML.StreamI(communicator, pw); + __os.marshalFacets(false); + v.ice_marshal("Value", __os); + return sw.toString().getBytes("UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + Ice.SyscallException e = new Ice.SyscallException(); + e.initCause(ex); + throw e; + } + } + + static ObjectRecord + unmarshalValue(byte[] b, Ice.Communicator communicator) + { + try + { + final String data = _header + new String(b, "UTF8") + _footer; + Ice.Stream __is = new IceXML.StreamI(communicator, new java.io.StringReader(data)); + Freeze.ObjectRecord __r = new Freeze.ObjectRecord(); + __r.ice_unmarshal("Value", __is); + return __r; + } + catch(java.io.UnsupportedEncodingException ex) + { + Ice.SyscallException e = new Ice.SyscallException(); + e.initCause(ex); + throw e; + } + } + private void init(String envName, String dbName, boolean createDb) { @@ -1041,20 +1393,24 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable private boolean dbHasObject(Ice.Identity ident) { + EvictorStorageKey esk = new EvictorStorageKey(); + esk.identity = ident; + esk.facet = null; + + byte[] key = marshal(esk, _communicator); + + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); + + // + // Keep 0 length since we're not interested in the data + // + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); + dbValue.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); + for(;;) { try - { - byte[] key = IdentityObjectRecordDict.encodeKeyImpl(ident, _communicator); - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); - - // - // Keep 0 length since we're not interested in the data - // - com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); - dbValue.set_flags(com.sleepycat.db.Db.DB_DBT_USERMEM | - com.sleepycat.db.Db.DB_DBT_PARTIAL); - + { int err = _db.get(null, dbKey, dbValue, 0); if(err == 0) @@ -1087,34 +1443,124 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable } } - private ObjectRecord - getObject(Ice.Identity ident) + + private void + addToModifiedQueue(Facet facet) { - byte[] key = IdentityObjectRecordDict.encodeKeyImpl(ident, _communicator); - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); + facet.element.usageCount++; + _modifiedQueue.add(facet); + + if(_saveSizeTrigger >= 0 && _modifiedQueue.size() >= _saveSizeTrigger) + { + notifyAll(); + } + } + + private void + saveNowNoSync() + { + Thread myself = Thread.currentThread(); + + _saveNowThreads.add(myself); + notifyAll(); + do + { + try + { + wait(); + } + catch(InterruptedException ex) + { + } + } while(_saveNowThreads.contains(myself)); + } + + private byte[] + writeObjectRecordToValue(long saveStart, ObjectRecord rec) + { + // + // Update stats first + // + Statistics stats = rec.stats; + long diff = saveStart - (stats.creationTime + stats.lastSaveTime); + if(stats.lastSaveTime == 0) + { + stats.lastSaveTime = diff; + stats.avgSaveTime = diff; + } + else + { + stats.lastSaveTime = saveStart - stats.creationTime; + stats.avgSaveTime = (long)(stats.avgSaveTime * 0.95 + diff * 0.05); + } + return marshal(rec, _communicator); + } + + private EvictorElement + load(Ice.Identity ident) + { + EvictorStorageKey esk = new EvictorStorageKey(); + esk.identity = ident; + esk.facet = null; + byte[] root = marshalRoot(esk, _communicator); + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(root); com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); + EvictorElement result = null; for(;;) { + result = new EvictorElement(); + + com.sleepycat.db.Dbc dbc = null; + try { - int err = _db.get(null, dbKey, dbValue, 0); - - if(err == 0) - { - return (ObjectRecord) IdentityObjectRecordDict.decodeValueImpl( - dbValue.get_data(), _communicator); - } - else if(err == com.sleepycat.db.Db.DB_NOTFOUND) - { + dbc = _db.cursor(null, 0); + + // + // Get first pair + // + int rs = dbc.get(dbKey, dbValue, com.sleepycat.db.Db.DB_SET_RANGE); + + if(rs != 0 || !startWith(dbKey.get_data(), root)) + { + if(_trace >= 2) + { + _communicator.getLogger().trace( + "Freeze::Evictor", + "could not find \"" + Ice.Util.identityToString(ident) + + "\" in the database"); + } return null; } - else + + do { - assert(false); - throw new DBException(); + // + // Unmarshal key and data and insert it into result's facet map + // + esk = unmarshalKey(dbKey.get_data(), _communicator); + + Facet facet = new Facet(result); + facet.status = clean; + facet.rec = unmarshalValue(dbValue.get_data(), _communicator); + facet.path = esk.facet; + assert(facet.path != null); + result.facets.put(new StringArray(esk.facet), facet); + if(esk.facet.length == 0) + { + result.mainObject = facet; + } + + // + // Next facet + // + rs = dbc.get(dbKey, dbValue, com.sleepycat.db.Db.DB_NEXT); } + while(rs == 0 && startWith(dbKey.get_data(), root)); + + break; // for (;;) } catch(com.sleepycat.db.DbDeadlockException deadlock) { @@ -1129,61 +1575,277 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable ex.message = _errorPrefix + "Db.get: " + dx.getMessage(); throw ex; } + finally + { + if(dbc != null) + { + try + { + dbc.close(); + dbc = null; + } + catch(com.sleepycat.db.DbException dx) + { + } + } + } } - } - private void - addToModifiedQueue(Ice.Identity ident, EvictorElement element) - { - element.usageCount++; - _modifiedQueue.add(ident); + // + // Let's fix-up the facets tree in result + // + java.util.Iterator p = result.facets.entrySet().iterator(); - if(_saveSizeTrigger >= 0 && _modifiedQueue.size() >= _saveSizeTrigger) + while(p.hasNext()) { - notifyAll(); + java.util.Map.Entry entry = (java.util.Map.Entry) p.next(); + + String[] path = ((StringArray) entry.getKey()).array; + + if(path.length > 0) + { + String[] parent = new String[path.length - 1]; + System.arraycopy(path, 0, parent, 0, path.length - 1); + Facet parentFacet = (Facet) result.facets.get(new StringArray(parent)); + if(parentFacet == null) + { + // + // TODO: log warning for this orphan facet + // + assert(false); + } + else + { + Facet childFacet = (Facet) entry.getValue(); + parentFacet.rec.servant.ice_addFacet(childFacet.rec.servant, path[path.length - 1]); + } + } } + + return result; } + private EvictorElement + insertElement(Ice.ObjectAdapter adapter, Ice.Identity ident, EvictorElement element) + { + if(_initializer != null) + { + _initializer.initialize(adapter, ident, element.mainObject.rec.servant); + } + + _evictorMap.put(ident, element); + _evictorList.addFirst(ident); + + element.position = _evictorList.iterator(); + // + // Position the iterator "on" the element. + // + element.position.next(); + + element.identity = ident; + return element; + } + private void - saveNowNoSync() + addFacetImpl(EvictorElement element, Ice.Object servant, String[] facetPath, boolean replacing) { - Thread myself = Thread.currentThread(); + java.util.Map facets = element.facets; + + boolean insertIt = true; - _saveNowThreads.add(myself); - notifyAll(); - do + StringArray facetPathArray = new StringArray(facetPath); + + if(replacing) { - try + Facet facet = (Facet) facets.get(facetPathArray); + if(facet != null) { - wait(); + synchronized(facet) + { + switch(facet.status) + { + case clean: + { + facet.status = modified; + addToModifiedQueue(facet); + break; + } + case created: + case modified: + { + // + // Nothing to do. + // No need to push it on the modified queue as a created resp + // modified facet is either already on the queue or about + // to be saved. When saved, it becomes clean. + // + break; + } + case destroyed: + { + facet.status = modified; + // + // No need to push it on the modified queue, as a destroyed facet + // is either already on the queue or about to be saved. When saved, + // it becomes dead. + // + break; + } + case dead: + { + facet.status = created; + addToModifiedQueue(facet); + break; + } + default: + { + assert(false); + break; + } + } + facet.rec.servant = servant; + insertIt = false; + } } - catch(InterruptedException ex) + } + + if(insertIt) + { + Facet facet = new Facet(element); + facet.status = created; + facet.path = facetPath; + + facet.rec = new ObjectRecord(); + ObjectRecord rec = facet.rec; + rec.servant = servant; + rec.stats = new Statistics(); + rec.stats.creationTime = System.currentTimeMillis(); + rec.stats.lastSaveTime = 0; + rec.stats.avgSaveTime = 0; + + facets.put(facetPathArray, facet); + if(facetPath.length == 0) { + element.mainObject = facet; } - } while(_saveNowThreads.contains(myself)); + addToModifiedQueue(facet); + } + + if(servant != null) + { + // + // Add servant's facets + // + String[] facetList = servant.ice_facets(null); + for(int i = 0; i < facetList.length; i++) + { + String[] newFacetPath = new String[facetPath.length + 1]; + System.arraycopy(facetPath, 0, newFacetPath, 0, facetPath.length); + String currentName = facetList[i]; + newFacetPath[newFacetPath.length - 1] = currentName; + addFacetImpl(element, servant.ice_findFacet(currentName), newFacetPath, replacing); + } + } } - - private byte[] - writeObjectRecordToValue(long saveStart, ObjectRecord rec) + + + private void + removeFacetImpl(java.util.Map facets, String[] facetPath) { + Facet facet = (Facet) facets.get(new StringArray(facetPath)); + Ice.Object servant = null; + + if(facet != null) + { + servant = destroyFacetImpl(facet); + } // - // Update stats first + // else should we raise an exception? // - Statistics stats = rec.stats; - long diff = saveStart - (stats.creationTime + stats.lastSaveTime); - if(stats.lastSaveTime == 0) + + if(servant != null) { - stats.lastSaveTime = diff; - stats.avgSaveTime = diff; + // + // Remove servant's facets + // + String[] facetList = servant.ice_facets(null); + for(int i = 0; i < facetList.length; i++) + { + String[] newFacetPath = new String[facetPath.length + 1]; + System.arraycopy(facetPath, 0, newFacetPath, 0, facetPath.length); + String currentName = facetList[i]; + newFacetPath[newFacetPath.length - 1] = currentName; + removeFacetImpl(facets, newFacetPath); + } } - else + } + + private Ice.Object + destroyFacetImpl(Facet facet) + { + synchronized(facet) { - stats.lastSaveTime = saveStart - stats.creationTime; - stats.avgSaveTime = (long)(stats.avgSaveTime * 0.95 + diff * 0.05); + switch(facet.status) + { + case clean: + { + facet.status = destroyed; + addToModifiedQueue(facet); + break; + } + case created: + { + facet.status = dead; + break; + } + case modified: + { + facet.status = destroyed; + // + // Not necessary to push it on the modified queue, as a modified + // element is either on the queue already or about to be saved + // (at which point it becomes clean) + // + break; + } + case destroyed: + case dead: + { + // + // Nothing to do! + // + break; + } + default: + { + assert(false); + break; + } + } + return facet.rec.servant; } - return IdentityObjectRecordDict.encodeValueImpl(rec, _communicator); } + private boolean + startWith(byte[] key, byte[] root) + { + if(key.length >= root.length) + { + for(int i = 0; i < root.length; i++) + { + if(key[i] != root[i]) + { + return false; + } + } + return true; + } + else + { + return false; + } + } + class StreamedObject { byte[] key; @@ -1191,16 +1853,73 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable byte status; }; - - class EvictorElement extends Ice.LocalObjectImpl + class EvictorElement { - byte status; - ObjectRecord rec; java.util.Iterator position; - int usageCount; + int usageCount = 0; + java.util.Map facets = new java.util.HashMap(); + Ice.Identity identity; + Facet mainObject; + }; + + class Facet extends Ice.LocalObjectImpl + { + Facet(EvictorElement evictorElement) + { + element = evictorElement; + } + byte status; + ObjectRecord rec; + EvictorElement element; + String[] path; }; // + // Wrapper to use a String[] as key of a HashMap. + // + class StringArray + { + StringArray(String[] a) + { + assert(a != null); + array = a; + } + + public boolean equals(java.lang.Object o) + { + if(o instanceof StringArray) + { + StringArray rhs = (StringArray) o; + if(rhs.array.length == array.length) + { + for(int i = 0; i < array.length; i++) + { + if(!array[i].equals(rhs.array[i])) + { + return false; + } + } + return true; + } + } + return false; + } + + public int hashCode() + { + int result = 0; + for(int i = 0; i < array.length; i++) + { + result ^= array[i].hashCode(); + } + return result; + } + + String[] array; + } + + + // // Clean object; can become modified or destroyed // private static final byte clean = 0; @@ -1244,9 +1963,9 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable private Freeze.LinkedList _evictorList = new Freeze.LinkedList(); // - // The _modifiedQueue contains a queue of all modified objects + // The _modifiedQueue contains a queue of all modified facets // Each element in the queue "owns" a usage count, to ensure the - // pointed element remains in the map. + // elements containing them remain in the map. // private java.util.List _modifiedQueue = new java.util.ArrayList(); @@ -1271,4 +1990,26 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable private Thread _thread; private String _errorPrefix; + + // + // _generation is incremented after committing changes + // to disk, when releasing the usage count of the element + // that contains the created/modified/destroyed facets. + // Like the usage count, it is protected by the Evictor mutex. + // + // It is used to detect updates when loading an element and its + // facets without holding the Evictor mutex. If the generation + // is the same before the loading and later when the Evictor + // mutex is locked again, and the map still does not contain + // this element, then the loaded value is current. + // + private int _generation = 0; + + + + private static final String _header = "<ice:data xmlns=\"http://www.noorg.org/schemas\"" + + " xmlns:ice=\"http://www.zeroc.com/schemas\"" + + " xmlns:xsi=\"http://www.w3.org/2003/XMLSchema-instance\"" + + " xsi:schemaLocation=\"http://www.noorg.org/schemas IdentityObjectRecordDict.xsd\">"; + private static final String _footer = "</ice:data>"; } diff --git a/java/src/Freeze/EvictorIteratorI.java b/java/src/Freeze/EvictorIteratorI.java index e82bdd40af3..d4c47177a03 100644 --- a/java/src/Freeze/EvictorIteratorI.java +++ b/java/src/Freeze/EvictorIteratorI.java @@ -40,31 +40,40 @@ class EvictorIteratorI extends Ice.LocalObjectImpl implements EvictorIterator com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); dbValue.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - try + for(;;) { - if(_dbc.get(dbKey, dbValue, com.sleepycat.db.Db.DB_NEXT) == 0) + try { - _current = (Ice.Identity) IdentityObjectRecordDict.decodeKeyImpl(dbKey.get_data(), _communicator); - return true; + if(_dbc.get(dbKey, dbValue, com.sleepycat.db.Db.DB_NEXT) == 0) + { + _current = EvictorI.unmarshalKey(dbKey.get_data(), _communicator); + if(_current.facet.length == 0) + { + return true; + } + // + // Otherwise loop + // + } + else + { + return false; + } } - else + catch(com.sleepycat.db.DbDeadlockException dx) { - return false; + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Dbc.get: " + dx.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Dbc.get: " + dx.getMessage(); + throw ex; } - } - catch(com.sleepycat.db.DbDeadlockException dx) - { - DBDeadlockException ex = new DBDeadlockException(); - ex.initCause(dx); - ex.message = _errorPrefix + "Dbc.get: " + dx.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException dx) - { - DBException ex = new DBException(); - ex.initCause(dx); - ex.message = _errorPrefix + "Dbc.get: " + dx.getMessage(); - throw ex; } } } @@ -74,7 +83,7 @@ class EvictorIteratorI extends Ice.LocalObjectImpl implements EvictorIterator { if(hasNext()) { - Ice.Identity result = _current; + Ice.Identity result = _current.identity; _current = null; return result; } @@ -146,7 +155,7 @@ class EvictorIteratorI extends Ice.LocalObjectImpl implements EvictorIterator private com.sleepycat.db.Dbc _dbc; - private Ice.Identity _current = null; + private EvictorStorageKey _current = null; private Ice.Communicator _communicator; private String _errorPrefix; } diff --git a/java/src/Ice/Object.java b/java/src/Ice/Object.java index 72a0e536a7e..e8d08afd670 100644 --- a/java/src/Ice/Object.java +++ b/java/src/Ice/Object.java @@ -38,7 +38,7 @@ public interface Object void __read(IceInternal.BasicStream __is, boolean __rid); - void __marshal(Ice.Stream __os); + void __marshal(Ice.Stream __os, boolean __marshalFacets); void __unmarshal(Ice.Stream __is); diff --git a/java/src/Ice/ObjectImpl.java b/java/src/Ice/ObjectImpl.java index 1bf0971c506..0600b15bd46 100644 --- a/java/src/Ice/ObjectImpl.java +++ b/java/src/Ice/ObjectImpl.java @@ -264,25 +264,33 @@ public class ObjectImpl implements Object, java.lang.Cloneable } public void - __marshal(Ice.Stream __os) + __marshal(Ice.Stream __os, boolean __marshalFacets) { - synchronized(_activeFacetMap) - { - final int sz = _activeFacetMap.size(); + if(__marshalFacets) + { + synchronized(_activeFacetMap) + { + final int sz = _activeFacetMap.size(); + + __os.startWriteDictionary("ice:facets", sz); + java.util.Set set = _activeFacetMap.keySet(); + String[] keys = new String[sz]; + set.toArray(keys); + for(int i = 0; i < sz; i++) + { + __os.startWriteDictionaryElement(); + __os.writeString("ice:key", keys[i]); + __os.writeObject("ice:value", (Object)_activeFacetMap.get(keys[i])); + __os.endWriteDictionaryElement(); + } + } + } + else + { + __os.startWriteDictionary("ice:facets", 0); + } - __os.startWriteDictionary("ice:facets", sz); - java.util.Set set = _activeFacetMap.keySet(); - String[] keys = new String[sz]; - set.toArray(keys); - for(int i = 0; i < sz; i++) - { - __os.startWriteDictionaryElement(); - __os.writeString("ice:key", keys[i]); - __os.writeObject("ice:value", (Object)_activeFacetMap.get(keys[i])); - __os.endWriteDictionaryElement(); - } - __os.endWriteDictionary(); - } + __os.endWriteDictionary(); } public void diff --git a/java/src/Ice/PropertiesI.java b/java/src/Ice/PropertiesI.java index 6a0cc2b5acb..cbf6ab926e1 100644 --- a/java/src/Ice/PropertiesI.java +++ b/java/src/Ice/PropertiesI.java @@ -551,7 +551,8 @@ final class PropertiesI extends LocalObjectImpl implements Properties { "Trace.DB", "Trace.Evictor", - "Evictor.*" + "Evictor.*", + "db.*" // Temporary }; private static final class ValidProps diff --git a/java/src/IceXML/StreamI.java b/java/src/IceXML/StreamI.java index c866cbc340a..189a7d52720 100644 --- a/java/src/IceXML/StreamI.java +++ b/java/src/IceXML/StreamI.java @@ -1171,6 +1171,12 @@ public class StreamI extends Ice.LocalObjectImpl implements Ice.Stream return value; } + public void + marshalFacets(boolean setting) + { + _marshalFacets = setting; + } + private void startWrite(String name) { @@ -1324,7 +1330,7 @@ public class StreamI extends Ice.LocalObjectImpl implements Ice.Stream startWrite(s); if(obj != null) { - obj.__marshal(this); + obj.__marshal(this, _marshalFacets); } endWrite(); } @@ -1553,6 +1559,7 @@ public class StreamI extends Ice.LocalObjectImpl implements Ice.Stream } private java.util.IdentityHashMap _objects; private boolean _dump; + private boolean _marshalFacets = true; private static class DOMTreeErrorReporter implements org.xml.sax.ErrorHandler { |