[OJB-developers] Re: Named Root Objects
Brought to you by:
thma
From: Michael N. <mic...@gm...> - 2002-01-14 21:10:42
|
Hi Thomas! I've been thinking about the GC process over the last few days. > Currently there is no GC implemented. > IMHO it will be VERY difficult to have a real GC as it would be possible > with an OODBMS. > It will be very difficult to decide if objects can safely be deleted. > > BUT: we have been thinking of changing the semantics of DList.remove() > an similar methods as name roots unbind so that removed objects are > deleted from the DB. A first step towards true persistence by reachability could be to offer offline GC. This way you don't have the to deal with objects which not reachable from any named root object any more but are still referenced under another transaction that has not yet committed. The algorithm could look like this: 1. Make a list of all objects stored in the database 2. from every named root object traverse the object graph and mark any object you come across as being persistent 3. delete all the objects from the database which are currently not marked as persistent. The algorithm can be implemented using recursion. In order to avoid indefinite loops caused by cyclic references, the algorithm has to check whether an object under investigation is already marked. Another advantage is that people who do not want seamless persistence the "Java Way" but instead want to have a more basic level control over their data still have the option not to execute the garbage collector. What do you think about it? Greetings Michael ----- Original Message ----- From: "Thomas Mahler" <tho...@ho...> To: "Michael Nowotny" <mic...@gm...>; "ojb" <obj...@li...> Sent: Wednesday, January 09, 2002 6:51 PM Subject: Re: Named Root Objects > Hi again, > > > Michael Nowotny wrote: > > > Hi Thomas! > > > > Thanks for the illustration. Binding collections works fine for me now! > > The reason why my earlier attempt failed was that I was still using > > InstantDB.It seems that some transactions got only halfway commited due to > > program termination following db.close(). Now I'm using Hypersonic and > > everything works. > > > > Fine ! > > > > During the course of setting up a test procedure I came across some strange > > behaviour. The following code snipped throws an ObjectNameNotBoundException. > > > > // fails: > > tx = odmg.newTransaction(); > > tx.begin(); > > db.bind(odmg.newDList(), "MyList"); > > db.unbind("MyList"); > > db.bind(odmg.newDList(), "MyList"); > > // DList list = (DList)db.lookup("MyList"); > > tx.commit(); > > > > tx = odmg.newTransaction(); > > tx.begin(); > > DList newList = (DList)db.lookup("MyList"); > > tx.commit(); > > > > Binding the same name twice within the same transaction seems to cause an > > error. > > > Oops, This is a bug. I'll add it to my todo list! > > > This is not very important though because usually one wouldn't want > > to bind an object to a some name and thereafter unbinding that name withing > > the same transaction. > > > > Another question arose when I had a look at the contents of my database. If > > I add content to my list which is a named root object this content gets > > persistent as well. That's part of persistence by reachability. But when I > > unbind the root object and the content is therefore no longer reachable, it > > doesn't get removed from the database but is still present. Is there any way > > of performing some kind of garbage collection? > > > > > > Currently there is no GC implemented. > IMHO it will be VERY difficult to have a real GC as it would be possible > with an OODBMS. > It will be very difficult to decide if objects can safely be deleted. > > BUT: we have been thinking of changing the semantics of DList.remove() > an similar methods as name roots unbind so that removed objects are > deleted from the DB. > > Any ideas? > > -- Thomas > > > > > > Keep up the good work! > > > > Thanks, Michael > > > > ----- Original Message ----- > > From: "Thomas Mahler" <tho...@ho...> > > To: "Michael Nowotny" <mic...@gm...>; "ojb" > > <obj...@li...> > > Sent: Tuesday, January 08, 2002 8:20 PM > > Subject: Re: Named Root Objects > > > > > > > >>Hi Michael, > >> > >>please see the attached Java class. > >> > >>You can replace the original version of test.ojb.odmg.OdmgExamples with > >>this new version to have it executed with the OJB JUnit tests. > >> > >>There is a new testMethod testNrmAndDlists that tests your scenario. > >>Works great! > >> > >>HTH, > >> > >>Thomas > >> > >>Michael Nowotny wrote: > >> > >> > >>>Hi Thomas! > >>> > >>>Just found your OJB project on sourceforge. I think it's great to have > >>> > > an > > > >>>open source ODMG implementation around. > >>>Now I've got a question concerning the ODMG implemetation. > >>>Is it possible to use a DList for example as a named root object. > >>> > > Binding > > > >>>that object to a name works but looking it up again causes an > >>>IllegalArgumentException. > >>> > >>>Have you ever tried to bind a Collection. If so, I would be grateful if > >>> > > you > > > >>>could drop me some lines of source code. > >>> > >>>Thanks Michael > >>> > >>> > >>> > >>> > >>> > >>> > >> > >> > > > > > > -------------------------------------------------------------------------- -- > > ---- > > > > > > > >>package test.ojb.odmg; > >> > >> > >>import junit.framework.TestCase; > >>import ojb.broker.Identity; > >>import ojb.broker.PersistenceBroker; > >>import ojb.broker.PersistenceBrokerFactory; > >>import ojb.broker.cache.ObjectCacheFactory; > >>import ojb.odmg.OJB; > >>import ojb.odmg.states.ModificationState; > >>import ojb.odmg.states.StateNewClean; > >>import ojb.odmg.states.StateNewDirty; > >>import org.odmg.*; > >> > >>import java.util.List; > >> > >>/** Demo Application that shows basic concepts for Applications using the > >> > > OJB ODMG > > > >> * implementation as an transactional object server. > >> */ > >>public class OdmgExamples extends TestCase > >>{ > >> public static void main(String[] args) > >> { > >> String[] arr = {CLASS.getName()}; > >> junit.textui.TestRunner.main(arr); > >> } > >> > >> private static Class CLASS = OdmgExamples.class; > >> private String databaseName; > >> > >> /** > >> * Insert the method's description here. > >> * Creation date: (24.12.2000 00:33:40) > >> */ > >> public OdmgExamples(String name) > >> { > >> super(name); > >> } > >> > >> /** > >> * Insert the method's description here. > >> * Creation date: (06.12.2000 21:58:53) > >> */ > >> public void setUp() > >> { > >> databaseName = > >> > > PersistenceBrokerFactory.getConfiguration().getRepositoryFilename(); > > > >> > >> } > >> > >> /** > >> * Insert the method's description here. > >> * Creation date: (06.12.2000 21:59:14) > >> */ > >> public void tearDown() > >> { > >> databaseName = null; > >> } > >> > >> /**TestThreadsNLocks state transition of modification states*/ > >> public void testModificationStates() > >> { > >> // get facade instance > >> Implementation odmg = OJB.getInstance(); > >> Database db = odmg.newDatabase(); > >> //open database > >> try > >> { > >> db.open(databaseName, Database.OPEN_READ_WRITE); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> ModificationState oldState = StateNewClean.getInstance(); > >> ModificationState newState = oldState.markDirty(); > >> assertEquals(StateNewDirty.getInstance(), newState); > >> > >> oldState = newState; > >> newState = oldState.markDirty(); > >> assertEquals(oldState, newState); > >> > >> > >> // close database > >> try > >> { > >> db.close(); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> > >> } > >> > >> public void testOdmgSession() > >> { > >> // get facade instance > >> Implementation odmg = OJB.getInstance(); > >> Database db = odmg.newDatabase(); > >> //open database > >> try > >> { > >> db.open(databaseName, Database.OPEN_READ_WRITE); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> Transaction tx = odmg.newTransaction(); > >> > >> //perform transaction > >> try > >> { > >> tx.begin(); > >> > >> Article example = new Article(); > >> example.setArticleId(777); > >> db.makePersistent(example); > >> > >> > >> > >> // modify Object > >> example.setStock(333); > >> example.addToStock(47); > >> example.addToStock(7); > >> example.addToStock(4); > >> > >> > >> //System.out.println("now commit all changes..."); > >> tx.commit(); > >> } > >> catch (Exception ex) > >> { > >> tx.abort(); > >> } > >> > >> // close database > >> try > >> { > >> db.close(); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> } > >> > >> public void testOQLQuery() > >> { > >> // get facade instance > >> Implementation odmg = OJB.getInstance(); > >> Database db = odmg.newDatabase(); > >> //open database > >> try > >> { > >> db.open(databaseName, Database.OPEN_READ_WRITE); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> Transaction tx = odmg.newTransaction(); > >> > >> //perform transaction > >> try > >> { > >> tx.begin(); > >> > >> > >> OQLQuery query = odmg.newOQLQuery(); > >> query.create("select anArticle from " + > >> > > Article.class.getName() + " where articleId = 7"); > > > >> List results = (List) query.execute(); > >> > >> Article a = (Article) results.get(0); > >> > >> > >> // cross check with PersistenceBroker lookup > >> // 1. get OID > >> Article example = new Article(); > >> example.setArticleId(7); > >> Identity oid = new Identity(example); > >> // 2. lookup object by OID > >> PersistenceBroker broker = OJB.getInstance().getBroker(); > >> broker.clearCache(); > >> Article b = (Article) broker.getObjectByIdentity(oid); > >> > >> assertEquals("should be same object", a, b); > >> > >> //System.out.println("now commit all changes..."); > >> tx.commit(); > >> } > >> catch (Exception ex) > >> { > >> tx.abort(); > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> > >> // close database > >> try > >> { > >> db.close(); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> } > >> > >> public void testNrmAndDlists() > >> { > >> // get facade instance > >> Implementation odmg = OJB.getInstance(); > >> Database db = odmg.newDatabase(); > >> //open database > >> try > >> { > >> db.open(databaseName, Database.OPEN_READ_WRITE); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> Transaction tx = odmg.newTransaction(); > >> > >> //perform transaction > >> try > >> { > >> tx.begin(); > >> > >> > >> OQLQuery query = odmg.newOQLQuery(); > >> query.create("select x from " + Article.class.getName() + " > >> > > where productGroupId = 7"); > > > >> DList results = (DList) query.execute(); > >> > >> > >> int originalSize = results.size(); > >> > >> OJB.getLogger().info(results); > >> > >> String name = "gimme fruits !"; > >> > >> db.bind(results, name); > >> tx.commit(); > >> > >> // clear the cache to make sure things are loaded from RDBMS ! > >> OJB.getInstance().getBroker().clearCache(); > >> > >> tx = odmg.newTransaction(); > >> tx.begin(); > >> > >> // look it up again > >> DList newResults = (DList) db.lookup(name); > >> > >> assertEquals(originalSize,newResults.size()); > >> OJB.getLogger().info(results); > >> > >> tx.commit(); > >> > >> > >> } > >> catch (Throwable t) > >> { > >> tx.abort(); > >> fail("ODMGException: " + t.getMessage()); > >> } > >> > >> // close database > >> try > >> { > >> db.close(); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> } > >> > >> > >> > >> public void testOQLQueryBind() > >> { > >> // get facade instance > >> Implementation odmg = OJB.getInstance(); > >> Database db = odmg.newDatabase(); > >> //open database > >> try > >> { > >> db.open(databaseName, Database.OPEN_READ_WRITE); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> Transaction tx = odmg.newTransaction(); > >> > >> //perform transaction > >> try > >> { > >> tx.begin(); > >> > >> > >> OQLQuery query = odmg.newOQLQuery(); > >> query.create("select anArticle from " + > >> > > Article.class.getName() + " where articleId = $678"); > > > >> query.bind(new Integer(7)); > >> > >> List results = (List) query.execute(); > >> > >> Article a = (Article) results.get(0); > >> > >> //crosscheck with PersistenceBroker lookup > >> // 1. get OID > >> Article example = new Article(); > >> example.setArticleId(7); > >> Identity oid = new Identity(example); > >> > >> ObjectCacheFactory.getObjectCache().clear(); > >> // 2. lookup object by OID > >> PersistenceBroker broker = OJB.getInstance().getBroker(); > >> broker.clearCache(); > >> Article b = (Article) broker.getObjectByIdentity(oid); > >> > >> assertEquals("should be same object", a, b); > >> > >> //System.out.println("now commit all changes..."); > >> tx.commit(); > >> } > >> catch (Exception ex) > >> { > >> tx.abort(); > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> > >> // close database > >> try > >> { > >> db.close(); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> } > >> > >> public void tesOQLQueryOnCollections() > >> { > >> // get facade instance > >> Implementation odmg = OJB.getInstance(); > >> Database db = odmg.newDatabase(); > >> //open database > >> try > >> { > >> db.open(databaseName, Database.OPEN_READ_WRITE); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> Transaction tx = odmg.newTransaction(); > >> > >> //perform transaction > >> try > >> { > >> tx.begin(); > >> OQLQuery query = odmg.newOQLQuery(); > >> query.create("select aLotOfArticles from " + > >> > > Article.class.getName() + " where productGroupId = 4"); > > > >> DCollection results = (DCollection) query.execute(); > >> results = results.query("price > 35"); > >> > >> // now perform control query > >> query = odmg.newOQLQuery(); > >> query.create("select aLotOfArticles from " + > >> > > Article.class.getName() + " where productGroupId = 4 and price > 35"); > > > >> DCollection check = (DCollection) query.execute(); > >> > >> assertEquals(results, check); > >> > >> > >> tx.commit(); > >> } > >> catch (Exception ex) > >> { > >> tx.abort(); > >> ex.printStackTrace(); > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> > >> // close database > >> try > >> { > >> db.close(); > >> } > >> catch (ODMGException ex) > >> { > >> fail("ODMGException: " + ex.getMessage()); > >> } > >> } > >> > >> > >> /**try to open non-existing db*/ > >> public void tesWrongDbName() > >> { > >> // get facade instance > >> OJB objectserver = OJB.getInstance(); > >> Database db = objectserver.newDatabase(); > >> > >> //try open database with non existing repository file: > >> String wrongDatabaseName = "ThereIsNoSuchFile"; > >> try > >> { > >> db.open(wrongDatabaseName, Database.OPEN_READ_WRITE); > >> fail("should not be able to open database " + > >> > > wrongDatabaseName); > > > >> } > >> catch (ODMGException ex) > >> { > >> return; > >> } > >> } > >>} > >> > >> > > > > > > > > > > > |