/* * Copyright 2009-2016 Tilmann Zaeschke. All rights reserved. * * This file is part of ZooDB. * * ZooDB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ZooDB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ZooDB. If not, see <http://www.gnu.org/licenses/>. * * See the README and COPYING files for further information. */ package org.zoodb.test.jdo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import javax.jdo.JDOFatalDataStoreException; import javax.jdo.JDOFatalUserException; import javax.jdo.JDOHelper; import javax.jdo.JDOOptimisticVerificationException; import javax.jdo.JDOUserException; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.zoodb.internal.server.DiskAccessOneFile; import org.zoodb.jdo.ZooJdoHelper; import org.zoodb.jdo.ZooJdoProperties; import org.zoodb.schema.ZooClass; import org.zoodb.schema.ZooSchema; import org.zoodb.test.api.TestSuper; import org.zoodb.test.testutil.TestTools; public class Test_022_MultiSessionSchema { @Before public void setUp() { DiskAccessOneFile.allowReadConcurrency(true); TestTools.removeDb(); TestTools.createDb(); } @After public void tearDown() { DiskAccessOneFile.allowReadConcurrency(false); TestTools.removeDb(); } @Test public void testCommitFailSchema() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); PersistenceManager pm1 = pmf.getPersistenceManager(); pm1.currentTransaction().begin(); ZooSchema s1 = ZooJdoHelper.schema(pm1); //new TestSuper(1, 11, null); ZooClass t11 = s1.defineEmptyClass("Class11"); s1.defineEmptyClass("Class22"); ZooClass t13 = s1.defineEmptyClass("Class33"); ZooClass t14 = s1.defineEmptyClass("Class44"); s1.defineEmptyClass("Class55"); //TODO test normal schema updates (new attr) and naming conflicts separately! //E.g. create class with name before cponciurring class is committed pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); PersistenceManager pm2 = pmf.getPersistenceManager(); pm2.currentTransaction().begin(); ZooSchema s2 = ZooJdoHelper.schema(pm2); //concurrent modification ZooClass t21 = s2.getClass("Class11"); ZooClass t22 = s2.getClass("Class22"); ZooClass t23 = s2.getClass("Class33"); ZooClass t24 = s2.getClass("Class44"); ZooClass t25 = s2.getClass("Class55"); //modified by both: t1, t3 //modified by 1: t4 //modified by 2: t5 t21.addField("_id", Long.TYPE); t23.rename("Class23"); t25.addField("_id", Long.class); t11.addField("_id2", Long.TYPE); t13.rename("Class13"); t14.addField("_id", Long.class); pm2.currentTransaction().commit(); pm2.currentTransaction().begin(); try { pm1.currentTransaction().commit(); fail(); } catch (JDOFatalDataStoreException e) { //good! assertFalse(e instanceof JDOOptimisticVerificationException); } assertTrue(pm1.isClosed()); assertEquals("_id", t21.getAllFields().get(0).getName()); assertEquals(0, t22.getAllFields().size()); assertEquals("Class23", t23.getName()); assertEquals(0, t24.getAllFields().size()); assertEquals("_id", t25.getAllFields().get(0).getName()); pm2.currentTransaction().rollback(); pm2.close(); pmf.close(); } @Test public void testCommitFailSchemaSmall() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); PersistenceManager pm1 = pmf.getPersistenceManager(); pm1.currentTransaction().begin(); PersistenceManager pm2 = pmf.getPersistenceManager(); pm2.currentTransaction().begin(); ZooSchema s2 = ZooJdoHelper.schema(pm2); //session 1 ZooSchema s1 = ZooJdoHelper.schema(pm1); s1.defineEmptyClass("Class11"); //concurrent modification try { s2.defineEmptyClass("Class11"); } catch (RuntimeException e) { e.printStackTrace(); } pm2.currentTransaction().commit(); pm2.currentTransaction().begin(); try { pm1.currentTransaction().commit(); fail(); } catch (JDOFatalDataStoreException e) { //good! assertFalse(e instanceof JDOOptimisticVerificationException); } assertTrue(pm1.isClosed()); pm2.currentTransaction().rollback(); pm2.close(); pmf.close(); } @Test public void testCommitFailWithDeleteSchema() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); PersistenceManager pm1 = pmf.getPersistenceManager(); pm1.currentTransaction().begin(); ZooSchema s1 = ZooJdoHelper.schema(pm1); //new TestSuper(1, 11, null); ZooClass t11 = s1.defineEmptyClass("Class11"); ZooClass t12 = s1.defineEmptyClass("Class22"); ZooClass t13 = s1.defineEmptyClass("Class33"); ZooClass t14 = s1.defineEmptyClass("Class44"); s1.defineEmptyClass("Class55"); //TODO test normal schema updates (new attr) and naming conflicts separately! //E.g. create class with name before cponciurring class is committed pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); PersistenceManager pm2 = pmf.getPersistenceManager(); pm2.currentTransaction().begin(); ZooSchema s2 = ZooJdoHelper.schema(pm2); //concurrent modification ZooClass t21 = s2.getClass("Class11"); ZooClass t22 = s2.getClass("Class22"); ZooClass t23 = s2.getClass("Class33"); //ZooClass t24 = s2.getClass("Class44"); ZooClass t25 = s2.getClass("Class55"); //deleted by both: t1 //del/mod t2, t3 //deleted by 1: t4 //deleted by 2: t5 t21.remove(); t22.remove(); t23.rename("Class23"); t25.remove(); t11.remove(); t12.rename("Class12"); t13.remove(); t14.remove(); pm2.currentTransaction().commit(); pm2.currentTransaction().begin(); try { pm1.currentTransaction().commit(); fail(); } catch (JDOFatalDataStoreException e) { //good! assertFalse(e instanceof JDOOptimisticVerificationException); } assertTrue(pm1.isClosed()); assertNull(s2.getClass("Class33")); assertNotNull(s2.getClass("Class23")); assertNull(s2.getClass("Class12")); assertNull(s2.getClass("Class22")); pm2.currentTransaction().rollback(); pm2.close(); pmf.close(); } @Test public void testSchemaDropInstances() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); TestTools.defineSchema(TestSuper.class); TestTools.defineSchema(TestClass.class); PersistenceManager pm1 = pmf.getPersistenceManager(); PersistenceManager pm2 = pmf.getPersistenceManager(); pm1.currentTransaction().begin(); pm2.currentTransaction().begin(); TestSuper t11 = new TestSuper(1, 11, null); //clean TestSuper t12 = new TestSuper(2, 22, null); //dirty TestSuper t13 = new TestSuper(3, 33, null); //deleted TestSuper t14 = new TestSuper(4, 44, null); TestSuper t15 = new TestSuper(5, 55, null); pm1.makePersistent(t11); pm1.makePersistent(t12); pm1.makePersistent(t13); pm1.makePersistent(t14); pm1.makePersistent(t15); pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); //concurrent modification TestClass t21 = new TestClass(); TestClass t22 = new TestClass(); TestClass t23 = new TestClass(); pm2.makePersistent(t21); pm2.makePersistent(t22); pm2.makePersistent(t23); //clean: t1 //deleted t2 //update: t3 //delete class of other tx pm2.deletePersistent(t22); t23.setInt(23); ZooJdoHelper.schema(pm2).getClass(TestSuper.class).dropInstances(); pm1.deletePersistent(t12); t13.setId(13); ZooJdoHelper.schema(pm1).getClass(TestClass.class).dropInstances(); pm2.currentTransaction().commit(); pm2.currentTransaction().begin(); try { pm1.checkConsistency(); } catch (JDOFatalDataStoreException e) { //good } try { pm1.currentTransaction().commit(); fail(); } catch (JDOFatalUserException e) { //dropInstances is a schema operation! } assertTrue(pm1.isClosed()); assertTrue(JDOHelper.isDeleted(t22)); pm2.currentTransaction().rollback(); pm2.close(); pmf.close(); } @Test public void testSchemaDropClass() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); TestTools.defineSchema(TestSuper.class); TestTools.defineSchema(TestClass.class); PersistenceManager pm1 = pmf.getPersistenceManager(); PersistenceManager pm2 = pmf.getPersistenceManager(); pm1.currentTransaction().begin(); pm2.currentTransaction().begin(); TestSuper t11 = new TestSuper(1, 11, null); //clean TestSuper t12 = new TestSuper(2, 22, null); //dirty TestSuper t13 = new TestSuper(3, 33, null); //deleted TestSuper t14 = new TestSuper(4, 44, null); TestSuper t15 = new TestSuper(5, 55, null); pm1.makePersistent(t11); pm1.makePersistent(t12); pm1.makePersistent(t13); pm1.makePersistent(t14); pm1.makePersistent(t15); pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); //concurrent modification TestClass t21 = new TestClass(); TestClass t22 = new TestClass(); TestClass t23 = new TestClass(); pm2.makePersistent(t21); pm2.makePersistent(t22); pm2.makePersistent(t23); //clean: t1 //deleted t2 //update: t3 //delete class of other tx pm2.deletePersistent(t22); t23.setInt(23); ZooJdoHelper.schema(pm2).getClass(TestSuper.class).remove(); pm1.deletePersistent(t12); t13.setId(13); ZooJdoHelper.schema(pm1).getClass(TestClass.class).remove(); pm2.currentTransaction().commit(); pm2.currentTransaction().begin(); try { pm1.checkConsistency(); } catch (JDOFatalDataStoreException e) { //good } try { pm1.currentTransaction().commit(); fail(); } catch (JDOFatalUserException e) { //good --> schema change } assertTrue(pm1.isClosed()); //assert FALSE, because the class TestClass is still there, only TestSuper was removed! assertFalse(JDOHelper.isDeleted(t21)); assertFalse(JDOHelper.isDeleted(t23)); pm2.currentTransaction().rollback(); pm2.close(); pmf.close(); } @Test public void testSchemaAttrIndexUpdates() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); TestTools.defineSchema(TestSuper.class); TestTools.defineSchema(TestClass.class); PersistenceManager pm1 = pmf.getPersistenceManager(); PersistenceManager pm2 = pmf.getPersistenceManager(); pm1.currentTransaction().begin(); pm2.currentTransaction().begin(); TestSuper t11 = new TestSuper(1, 11, null); TestSuper t12 = new TestSuper(2, 22, null); TestSuper t13 = new TestSuper(3, 33, null); pm1.makePersistent(t11); pm1.makePersistent(t12); pm1.makePersistent(t13); ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_id").createIndex(false); pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); ZooJdoHelper.schema(pm2).getClass(TestSuper.class).getField("_id").createIndex(false); try { pm2.currentTransaction().commit(); fail(); } catch (JDOOptimisticVerificationException e) { //good! } pm2.currentTransaction().rollback(); pm2.currentTransaction().begin(); //try again ZooJdoHelper.schema(pm2).getClass(TestSuper.class).getField("_time").createIndex(false); pm2.currentTransaction().commit(); pm2.currentTransaction().begin(); assertTrue(ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_id").hasIndex()); //Well, pm1 simply does not know yet that this is indexed... //assertTrue(ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_time").hasIndex()); assertTrue(ZooJdoHelper.schema(pm2).getClass(TestSuper.class).getField("_id").hasIndex()); assertTrue(ZooJdoHelper.schema(pm2).getClass(TestSuper.class).getField("_time").hasIndex()); pm1.currentTransaction().rollback(); pm2.currentTransaction().rollback(); pm1.close(); pm2.close(); pmf.close(); } @Test public void testSchemaAttrIndexUpdatesUnique() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); TestTools.defineSchema(TestSuper.class); TestTools.defineSchema(TestClass.class); PersistenceManager pm1 = pmf.getPersistenceManager(); PersistenceManager pm2 = pmf.getPersistenceManager(); pm1.currentTransaction().begin(); pm2.currentTransaction().begin(); TestSuper t11 = new TestSuper(1, 11, null); TestSuper t12 = new TestSuper(2, 22, null); TestSuper t13 = new TestSuper(3, 33, null); pm1.makePersistent(t11); pm1.makePersistent(t12); pm1.makePersistent(t13); ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_id").createIndex(true); pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); //concurrent modification TestSuper t21 = new TestSuper(1, 11, null); pm2.makePersistent(t21); try { pm2.currentTransaction().commit(); fail(); } catch (JDOUserException e) { //good! assertTrue(e.getMessage().contains("Unique index clash")); } //try again pm2.currentTransaction().begin(); t21.setId(21); pm2.makePersistent(t21); pm2.currentTransaction().commit(); pm2.currentTransaction().begin(); ZooJdoHelper.schema(pm2).getClass(TestSuper.class).getField("_time").createIndex(true); try { pm2.currentTransaction().commit(); fail(); } catch (JDOUserException e) { //good! assertTrue(e.getMessage().contains("Duplicate entry")); } pm2.currentTransaction().begin(); //okay fix it in session 1 t11.setTime(1234); pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); //try again ZooJdoHelper.schema(pm2).getClass(TestSuper.class).getField("_time").createIndex(true); pm2.currentTransaction().commit(); pm2.currentTransaction().begin(); assertTrue(ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_id").hasIndex()); //Well, pm1 simply does not know yet that this is indexed... //assertTrue(ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_time").hasIndex()); assertTrue(ZooJdoHelper.schema(pm2).getClass(TestSuper.class).getField("_id").hasIndex()); assertTrue(ZooJdoHelper.schema(pm2).getClass(TestSuper.class).getField("_time").hasIndex()); pm1.currentTransaction().rollback(); pm2.currentTransaction().rollback(); pm1.close(); pm2.close(); pmf.close(); } @Test public void testSchemaAttrIndexUpdatesUniqueBug5() { ZooJdoProperties props = new ZooJdoProperties(TestTools.getDbName()); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); TestTools.defineSchema(TestSuper.class); PersistenceManager pm1 = pmf.getPersistenceManager(); pm1.currentTransaction().begin(); TestSuper t11 = new TestSuper(1, 11, null); TestSuper t12 = new TestSuper(2, 22, null); TestSuper t13 = new TestSuper(3, 33, null); pm1.makePersistent(t11); pm1.makePersistent(t12); pm1.makePersistent(t13); ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_id").createIndex(true); pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); //concurrent modification TestSuper t21 = new TestSuper(1, 11, null); pm1.makePersistent(t21); try { pm1.currentTransaction().commit(); fail(); } catch (JDOUserException e) { //good! assertTrue(e.getMessage().contains("Unique index clash")); } //try again pm1.currentTransaction().begin(); t21.setId(21); pm1.makePersistent(t21); pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_time").createIndex(true); try { pm1.currentTransaction().commit(); fail(); } catch (JDOUserException e) { //good! assertTrue(e.getMessage().contains("Duplicate entry")); } //okay fix it in session 1 pm1.currentTransaction().begin(); t11.setTime(1234); /////////// // The following commit failed because of 'duplicate entry'even though the index should // not be in the database at this point (it got rejected in the previous commit). /////////// pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); //try again ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_time").createIndex(true); pm1.currentTransaction().commit(); pm1.currentTransaction().begin(); assertTrue(ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_id").hasIndex()); assertTrue(ZooJdoHelper.schema(pm1).getClass(TestSuper.class).getField("_time").hasIndex()); pm1.currentTransaction().rollback(); pm1.close(); pmf.close(); } }