| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| package org.eclipse.persistence.testing.tests.jpa.performance.writing; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| |
| import jakarta.persistence.*; |
| |
| import org.eclipse.persistence.jpa.JpaEntityManager; |
| import org.eclipse.persistence.testing.framework.*; |
| import org.eclipse.persistence.testing.models.jpa.performance.Employee; |
| |
| /** |
| * This test compares the performance of inserting Employee. |
| */ |
| public class JPAMassInsertOrMergeEmployeeWithManagementLevelsPerformanceComparisonTest extends PerformanceRegressionTestCase { |
| // true indicates insert; false - merge. |
| boolean shouldInsert; |
| // true indicates that the pk value will be assigned by sequencing. |
| boolean shouldUseSequencing; |
| // number of management levels |
| int nLevels; |
| // number of direct subordinates each manager has |
| int nDirects; |
| // used to keep ids in case sequencing is not used |
| long id = 0; |
| |
| boolean wasBatchWriting; |
| |
| // Example: nLevels == 3; nDirects = 4. |
| // First all the Employees corresponding to nLevels and nDirects values are created: |
| // There is always the single (highest ranking) topEmployee on Level_0; |
| // He/she has 4 Level_1 direct subordinates; |
| // each of those has 4 Level_2 directs, |
| // each of those has 4 Level_3 directs. |
| // For debugging: |
| // Employee's firstName is always his level (in "Level_2" format); |
| // Employee's lastName is his number in his level (from 0 to number of employees of this level - 1) |
| // in "Number_3" format. |
| |
| public JPAMassInsertOrMergeEmployeeWithManagementLevelsPerformanceComparisonTest(boolean shouldInsert, boolean shouldUseSequencing, int nLevels, int nDirects) { |
| this.shouldInsert = shouldInsert; |
| this.shouldUseSequencing = shouldUseSequencing; |
| this.nLevels = nLevels; |
| this.nDirects = nDirects; |
| setName(getName() + (shouldInsert ? " insert" : " merge") + (shouldUseSequencing ? " useSequencing " : " doNotUseSequencing ") + " nLevel = " + nLevels + "; nDirects = " + nDirects); |
| setDescription("This test compares the performance of "+ (shouldInsert ? "insert" : "merge") + (shouldUseSequencing ? " useSequencing " : " doNotUseSequencing ") + " Employee with " + nLevels + " levels of management; each manager has " + nDirects + " direct employees"); |
| } |
| |
| @Override |
| public void setup() throws Exception { |
| id = 0; |
| // Disable batch writing, as seems to give database issues. |
| EntityManager entityManager = createEntityManager(); |
| if (entityManager instanceof JpaEntityManager) { |
| wasBatchWriting = ((JpaEntityManager)entityManager).getServerSession().getLogin().shouldUseBatchWriting(); |
| ((JpaEntityManager)entityManager).getServerSession().getLogin().setUsesBatchWriting(false); |
| } |
| entityManager.close(); |
| if(!shouldUseSequencing) { |
| // obtain the last used sequence number |
| Employee emp = new Employee(); |
| entityManager = createEntityManager(); |
| entityManager.getTransaction().begin(); |
| entityManager.persist(emp); |
| entityManager.getTransaction().commit(); |
| entityManager.close(); |
| id = emp.getId(); |
| entityManager = createEntityManager(); |
| entityManager.getTransaction().begin(); |
| emp = entityManager.find(Employee.class, emp.getId()); |
| entityManager.remove(emp); |
| entityManager.getTransaction().commit(); |
| entityManager.close(); |
| } |
| } |
| |
| /** |
| * Insert employee. |
| */ |
| @Override |
| public void test() throws Exception { |
| EntityManager manager = createEntityManager(); |
| try { |
| // topEmployee - the only one on level 0. |
| Employee topEmployee = new Employee(); |
| topEmployee.setFirstName("Level_0"); |
| topEmployee.setLastName("Number_0"); |
| if(!shouldUseSequencing) { |
| topEmployee.setId(id++); |
| } |
| |
| // During each nLevel loop iterartion |
| // this array contains direct managers for the Employees to be created - |
| // all the Employees of nLevel - 1 level. |
| ArrayList<Employee> employeesForHigherLevel = new ArrayList<Employee>(1); |
| // In the end of each nLevel loop iterartion |
| // this array contains all Employees created during this iteration - |
| // all the Employees of nLevel level. |
| ArrayList<Employee> employeesForCurrentLevel; |
| employeesForHigherLevel.add(topEmployee); |
| // total number of employees - for debugging purposes only. |
| int nEmployeesTotal = 1; |
| for (int nLevel = 1; nLevel <= nLevels; nLevel++) { |
| employeesForCurrentLevel = new ArrayList<Employee>(employeesForHigherLevel.size() * nDirects); |
| Iterator<Employee> it = employeesForHigherLevel.iterator(); |
| while(it.hasNext()) { |
| Employee mgr = it.next(); |
| for(int nCurrent = 0; nCurrent < nDirects; nCurrent++) { |
| Employee employee = new Employee(); |
| employee.setFirstName("Level_" + nLevel); |
| employee.setLastName("Number_" + employeesForCurrentLevel.size()); |
| if(!shouldUseSequencing) { |
| employee.setId(id++); |
| } |
| employeesForCurrentLevel.add(employee); |
| mgr.addManagedEmployee(employee); |
| } |
| } |
| employeesForHigherLevel = employeesForCurrentLevel; |
| nEmployeesTotal = nEmployeesTotal + employeesForCurrentLevel.size(); |
| } |
| |
| manager.getTransaction().begin(); |
| if(shouldInsert) { |
| manager.persist(topEmployee); |
| } else { |
| manager.merge(topEmployee); |
| } |
| manager.getTransaction().commit(); |
| } finally { |
| if(manager.getTransaction().isActive()) { |
| manager.getTransaction().rollback(); |
| } |
| manager.close(); |
| } |
| } |
| |
| @Override |
| public void reset() throws Exception { |
| // Delete all employees |
| EntityManager manager = createEntityManager(); |
| manager.getTransaction().begin(); |
| manager.createQuery("Delete from Employee where firstName like 'Level_%'").executeUpdate(); |
| manager.getTransaction().commit(); |
| manager.close(); |
| |
| // Re-enable batch writing. |
| EntityManager entityManager = createEntityManager(); |
| if (entityManager instanceof JpaEntityManager) { |
| ((JpaEntityManager)entityManager).getServerSession().getLogin().setUsesBatchWriting(wasBatchWriting); |
| } |
| entityManager.close(); |
| } |
| } |