/* * 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 java.util.Collection; import java.util.Iterator; import java.util.List; import javax.jdo.PersistenceManager; import javax.jdo.Query; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.zoodb.test.jdo.pole.CheckSummable; import org.zoodb.test.jdo.pole.ComplexHolder0; import org.zoodb.test.jdo.pole.ComplexHolder1; import org.zoodb.test.jdo.pole.ComplexHolder2; import org.zoodb.test.jdo.pole.ComplexHolder3; import org.zoodb.test.jdo.pole.ComplexHolder4; import org.zoodb.test.jdo.pole.NullVisitor; import org.zoodb.test.jdo.pole.Visitor; import org.zoodb.test.testutil.TestTools; public class Test_075_QueryComplexHolder { private Object rootId; //private long checkSum; private int nObjects; private int nSelects; private int depth; private PersistenceManager pm; @BeforeClass public static void beforeClass() { TestTools.removeDb(); TestTools.createDb(); TestTools.defineSchema(ComplexHolder0.class, ComplexHolder1.class, ComplexHolder2.class, ComplexHolder3.class, ComplexHolder4.class); } private void commit() { pm.currentTransaction().commit(); } private void begin() { pm.currentTransaction().begin(); } private PersistenceManager db() { return pm; } private void store(Object pc) { pm.makePersistent(pc); } private void delete(Object pc) { pm.deletePersistent(pc); } public void addToCheckSum(CheckSummable checkSummable){ addToCheckSum(checkSummable.checkSum()); } /** * Collecting a checksum to make sure every team does a complete job */ private synchronized void addToCheckSum(long l){ //checkSum += l; } private int objects() { return nObjects; } private int selects() { return nSelects; } private int depth() { return depth; } private void open() { pm = TestTools.openPM(); } private void close() { TestTools.closePM(); } /** * This failed with DataStreamCorrupted exception if makeDirty() was not called when setting * attributes. In that case, the update() failed for most objects. * It is unclear how this corrupted the database. * -> Temporary fix: do not set objects clean in ClientSessionCache.postCommit(). * * The problem was that the _usedClasses in the DataSerializer were reused for objects on the * written in the same stream (same page). Randomly accessing these objects meant that the * required used classes were not available, because they were only store with the first object. */ @Test public void test() { // run(1, 1, 4); run(1, 50, 4); // run(2, 50, 4); // run(3, 50, 4); // run(5, 500, 6); // run(6, 500, 6); // run(7, 500, 6); } protected void run(int objects, int selects, int depth) { System.out.println("o=" + objects + " s=" + selects + " d=" + depth); nObjects = objects; nSelects = selects; this.depth = depth; System.out.println("write()"); open(); write(); close(); open(); System.out.println("read()"); read(); close(); open(); System.out.println("query()"); query(); close(); open(); System.out.println("update()"); update(); close(); open(); System.out.println("delete()"); delete(); close(); } //@Override public Object write() { return write(false); } private Object write(boolean disjunctSpecial) { begin(); ComplexHolder0 holder = ComplexHolder0.generate(depth(), objects(), disjunctSpecial); addToCheckSum(holder); store(holder); rootId = db().getObjectId(holder); commit(); return rootId; } //@Override private void read() { begin(); db().getFetchPlan().addGroup("array"); db().getFetchPlan().addGroup("children"); db().getFetchPlan().setMaxFetchDepth(-1); ComplexHolder0 holder = read(rootId); addToCheckSum(holder); db().getFetchPlan().clearGroups(); commit(); } private ComplexHolder0 read(Object id) { return (ComplexHolder0) db().getObjectById(id); } //@Override private void query() { begin(); int selectCount = selects(); int firstInt = objects() * objects() + objects(); int lastInt = firstInt + (objects() * objects() * objects()) - 1; int currentInt = firstInt; for (int run = 0; run < selectCount; run++) { String filter = "this.i2 == param"; Query query = db().newQuery(db().getExtent(ComplexHolder2.class,true), filter); query.declareParameters("int param"); Collection<?> result = (Collection<?>) query.execute(currentInt); Iterator<?> it = result.iterator(); if(! it.hasNext()){ throw new IllegalStateException("no ComplexHolder2 found for i2=" + currentInt); } ComplexHolder2 holder = (ComplexHolder2) it.next(); if(it.hasNext()){ throw new IllegalStateException("more ComplexHolder2 found"); } addToCheckSum(holder.ownCheckSum()); List<ComplexHolder0> children = holder.getChildren(); for (ComplexHolder0 child : children) { addToCheckSum(child.ownCheckSum()); } ComplexHolder0[] array = holder.getArray(); for (ComplexHolder0 arrayElement : array) { addToCheckSum(arrayElement.ownCheckSum()); } currentInt++; if(currentInt > lastInt){ currentInt = firstInt; } } commit(); } //@Override private void update() { update(rootId); } private void update(Object id) { begin(); ComplexHolder0 holder = read(id); holder.traverse(new NullVisitor<ComplexHolder0>(), new Visitor<ComplexHolder0>() { @Override public void visit(ComplexHolder0 holder) { addToCheckSum(holder.ownCheckSum()); holder.setName("updated"); List<ComplexHolder0> children = holder.getChildren(); ComplexHolder0[] array = new ComplexHolder0[children.size()]; for (int i = 0; i < array.length; i++) { array[i] = children.get(i); } holder.setArray(array); } }); commit(); } //@Override private void delete() { deleteById(rootId); } private void deleteById(Object id) { begin(); ComplexHolder0 holder = read(id); holder.traverse( new NullVisitor<ComplexHolder0>(), new Visitor<ComplexHolder0>() { @Override public void visit(ComplexHolder0 holder) { addToCheckSum(holder.ownCheckSum()); delete(holder); } }); commit(); } @After public void afterTest() { TestTools.closePM(); } @AfterClass public static void tearDown() { TestTools.removeDb(); } }