/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.portfolio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.UUID; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.modules.fo.portfolio.ForumArtefact; import org.olat.portfolio.manager.EPFrontendManager; import org.olat.portfolio.manager.EPMapPolicy; import org.olat.portfolio.manager.EPMapPolicy.Type; import org.olat.portfolio.model.EPFilterSettings; import org.olat.portfolio.model.artefacts.AbstractArtefact; import org.olat.portfolio.model.structel.ElementType; import org.olat.portfolio.model.structel.PortfolioStructure; import org.olat.portfolio.model.structel.PortfolioStructureMap; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> * do queries to check for performance bottlenecks: * - Create a lot of artefacts, do load and searches * - create a lot of huge maps, publish them for all users, do searches * * <P> * Initial Date: 26.01.2011 <br> * * @author Roman Haag, roman.haag@frentix.com, http://www.frentix.com */ public class EPPerformanceTest extends OlatTestCase { private static final String LOREM_STRING_512 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id sapien ac justo congue mollis. " + "Sed pulvinar magna nec nulla gravida eu ullamcorper dolor mattis. Phasellus quis neque dolor. Aliquam non odio ligula. Integer purus nisi, " + "cursus accumsan ultricies eget, gravida sed eros. Maecenas malesuada commodo nisl, sit amet aliquam elit dapibus ut. Duis ultricies nibh at " + "felis commodo a rutrum ipsum tristique. Nulla facilisi. Vivamus convallis faucibus augue quis ultrices. Sed quam orci, dignissim metus. "; private static final List<String> tagList1 = new ArrayList<String>(Arrays.asList("Haus", "baum", "Wald")); private static final List<String> tagList2 = new ArrayList<String>(Arrays.asList("Schule", "Lehrer")); @Autowired private DB dbInstance; @Autowired private EPFrontendManager epFrontendManager; private static Identity ident1, ident2; private static boolean isInitialized = false; @Before public void setUp() { if (!isInitialized) { ident1 = JunitTestHelper.createAndPersistIdentityAsUser(UUID.randomUUID().toString()); ident2 = JunitTestHelper.createAndPersistIdentityAsUser(UUID.randomUUID().toString()); } } @After public void tearDown() { deleteMaps(); dbInstance.commitAndCloseSession(); } @Test public void testManagers() { assertNotNull(dbInstance); assertNotNull(epFrontendManager); } @Test public void testRealisticArtefactAmount(){ internalTestManyArtefactCreation(200); } @Test public void testHugeArtefactAmount(){ internalTestManyArtefactCreation(2000); } private void internalTestManyArtefactCreation(int artefactAmount){ long start = System.currentTimeMillis(); Runtime r = Runtime.getRuntime(); for (int j = 0; j < artefactAmount; j++) { AbstractArtefact artefact = createAndFillArtefact(j); // tag the artefacts if (j %2 == 0) { epFrontendManager.setArtefactTags(ident1, artefact, tagList1); } else { epFrontendManager.setArtefactTags(ident1, artefact, tagList2); } if (j % 10 == 0) { DBFactory.getInstance().closeSession(); } if (j % 100 == 0){ logger.info("created another 100 artefacts! -> " + j); logger.info(" free memory: " + r.freeMemory()); } } // for // load the whole artefact list long now = System.currentTimeMillis(); logger.info("created " + artefactAmount + " artefacts in: " + (now - start) + " ms."); start = System.currentTimeMillis(); List<AbstractArtefact> artList = epFrontendManager.getArtefactPoolForUser(ident1); now = System.currentTimeMillis(); logger.info("querying all of them took: " + (now - start) + " ms."); assertEquals(artList.size(), artefactAmount); // filter artefacts by tags EPFilterSettings filterSettings = new EPFilterSettings(); filterSettings.setTagFilter(new ArrayList<String>(Arrays.asList("Schule"))); start = System.currentTimeMillis(); artList = epFrontendManager.filterArtefactsByFilterSettings(filterSettings, ident1, new Roles(false, false, false, false, false, false, false)); now = System.currentTimeMillis(); logger.info("filter artefacts by one tag took: " + (now - start) + " ms."); assertEquals(artList.size(), artefactAmount/2); filterSettings.setTagFilter(tagList1); start = System.currentTimeMillis(); artList = epFrontendManager.filterArtefactsByFilterSettings(filterSettings, ident1, new Roles(false, false, false, false, false, false, false)); now = System.currentTimeMillis(); logger.info("filter artefacts by tagList1 took: " + (now - start) + " ms."); assertEquals(artList.size(), artefactAmount/2); } /** * create a heavy filled artefact! * @param j number of artefact * @return */ private AbstractArtefact createAndFillArtefact(int j) { AbstractArtefact artefact = epFrontendManager.createAndPersistArtefact(ident1, ForumArtefact.FORUM_ARTEFACT_TYPE); artefact.setFulltextContent(getLoremStringFactor512(2)); artefact.setReflexion(getLoremStringFactor512(3)); artefact.setDescription(LOREM_STRING_512); artefact.setTitle("Test Artefact number" + j); artefact.setSignature(60); artefact.setCollectionDate(new Date()); artefact.setBusinessPath("a dummy businessPath entry"); artefact.setSource("some Forum was my source"); return epFrontendManager.updateArtefact(artefact); } @Test public void testMaps500(){ internalTestCreateManyMaps(500); } private void deleteMaps(){ List<PortfolioStructure> publicMaps = epFrontendManager.getStructureElementsFromOthers(ident2, null, ElementType.STRUCTURED_MAP, ElementType.DEFAULT_MAP); int i=1; for (PortfolioStructure portfolioStructure : publicMaps) { i++; epFrontendManager.deletePortfolioStructure(portfolioStructure); if (i % 100 == 0) { DBFactory.getInstance().closeSession(); } } } private void internalTestCreateManyMaps(int mapAmount){ long start = System.currentTimeMillis(); // prepare some artefacts to link to maps later ArrayList<AbstractArtefact> artefacts = new ArrayList<AbstractArtefact>(10); for (int i = 1; i < 11; i++) { artefacts.add(createAndFillArtefact(i)); } for (int k = 1; k < mapAmount; k++) { PortfolioStructureMap map = epFrontendManager.createAndPersistPortfolioDefaultMap(ident1, "a test map number " + k, LOREM_STRING_512); // attach sites and structures to it ArrayList<PortfolioStructure> structs = new ArrayList<PortfolioStructure>(); PortfolioStructure page1 = epFrontendManager.createAndPersistPortfolioPage(map, "test page1 for map " + k, LOREM_STRING_512); structs.add(page1); PortfolioStructure struct11 = epFrontendManager.createAndPersistPortfolioStructureElement(page1, "struct1 in page1 for map" + k, LOREM_STRING_512); structs.add(struct11); PortfolioStructure struct12 = epFrontendManager.createAndPersistPortfolioStructureElement(page1, "struct2 in page1 for map" + k, LOREM_STRING_512); structs.add(struct12); PortfolioStructure page2 = epFrontendManager.createAndPersistPortfolioPage(map, "test page2 for map " + k, LOREM_STRING_512); structs.add(page2); PortfolioStructure struct21 = epFrontendManager.createAndPersistPortfolioStructureElement(page2, "struct1 in page2 for map" + k, LOREM_STRING_512); structs.add(struct21); PortfolioStructure struct22 = epFrontendManager.createAndPersistPortfolioStructureElement(page2, "struct2 in page2 for map" + k, LOREM_STRING_512); structs.add(struct22); // attach different artefacts to several places in map int l = 1; for (Iterator<PortfolioStructure> iterator = structs.iterator(); iterator.hasNext();) { PortfolioStructure portfolioStructure = iterator.next(); epFrontendManager.addArtefactToStructure(ident1, artefacts.get(l), portfolioStructure); // add two artefacts if (l % 2 == 0){ epFrontendManager.addArtefactToStructure(ident1, artefacts.get(l+1), portfolioStructure); } l++; } // for attach // share the map with all users EPMapPolicy userPolicy = new EPMapPolicy(); userPolicy.setType(Type.allusers); epFrontendManager.updateMapPolicies(map, Collections.singletonList(userPolicy)); dbInstance.commitAndCloseSession(); } // for maps long now = System.currentTimeMillis(); logger.info("created " + mapAmount + " maps, attached artefacts and shared maps to public in: " + (now - start) + " ms."); // load all maps start = System.currentTimeMillis(); List<PortfolioStructure> publicMaps = epFrontendManager.getStructureElementsFromOthers(ident2, null, ElementType.STRUCTURED_MAP, ElementType.DEFAULT_MAP); now = System.currentTimeMillis(); logger.info("got all public maps in: " + (now - start) + " ms."); // simulate queries done in EPMultipleMapController for all public maps: start = System.currentTimeMillis(); long sharedQ = 0; long countArtefactQ = 0; long countChildQ = 0; long qstart = 0; int j = 0; Runtime r = Runtime.getRuntime(); for (PortfolioStructure map : publicMaps) { j++; qstart = System.currentTimeMillis(); epFrontendManager.isMapShared((PortfolioStructureMap) map); sharedQ += System.currentTimeMillis() - qstart; qstart = System.currentTimeMillis(); epFrontendManager.countArtefactsInMap((PortfolioStructureMap) map); countArtefactQ += System.currentTimeMillis() - qstart; // lookup structured maps: if received from a template, would also do a lookup on repository entry! // EPTargetResource resource = structMap.getTargetResource(); // RepositoryEntry repoEntry = RepositoryManager.getInstance().lookupRepositoryEntry(resource.getOLATResourceable(), false); qstart = System.currentTimeMillis(); epFrontendManager.countStructureChildren(map); countChildQ += System.currentTimeMillis() - qstart; if (j % 100 == 0){ showStatsForStep(j, start, sharedQ, countArtefactQ, countChildQ, r); } } logger.info("============= get overall stats =============="); showStatsForStep(mapAmount, start, sharedQ, countArtefactQ, countChildQ, r); } /** * @param mapAmount * @param start * @param sharedQ * @param countArtefactQ * @param countChildQ */ private void showStatsForStep(int step, long start, long sharedQ, long countArtefactQ, long countChildQ, Runtime r) { long now; now = System.currentTimeMillis(); logger.info("---------------------------------------------"); logger.info("show actual query stats for step with " + step + " maps processed."); logger.info(" free memory: " + r.freeMemory()); logger.info(" simulated queries to show all public maps, took: " + (now - start) + " ms so far."); logger.info(" Q: share state average: " + (sharedQ / step) + " total: " + sharedQ); logger.info(" Q: artefact count average: " + (countArtefactQ / step) + " total: " + countArtefactQ); logger.info(" Q: child count average: " + (countChildQ / step) + " total: " + countChildQ); } private String getLoremStringFactor512(int factor){ StringBuffer sb = new StringBuffer(); for (int i = 0; i < factor; i++) { sb.append(LOREM_STRING_512); } return sb.toString(); } }