jmeter-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pmoua...@apache.org
Subject svn commit: r1611689 - in /jmeter/trunk: src/components/org/apache/jmeter/control/ src/components/org/apache/jmeter/control/gui/ src/core/org/apache/jmeter/resources/ xdocs/ xdocs/usermanual/
Date Fri, 18 Jul 2014 16:13:18 GMT
Author: pmouawad
Date: Fri Jul 18 16:13:18 2014
New Revision: 1611689

URL: http://svn.apache.org/r1611689
Log:
Bug 56728 - New Critical Section Controller to serialize blocks of a Test
Bugzilla Id: 56728

Added:
    jmeter/trunk/src/components/org/apache/jmeter/control/CriticalSectionController.java 
 (with props)
    jmeter/trunk/src/components/org/apache/jmeter/control/gui/CriticalSectionControllerGui.java
  (with props)
Modified:
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
    jmeter/trunk/xdocs/changes.xml
    jmeter/trunk/xdocs/usermanual/component_reference.xml

Added: jmeter/trunk/src/components/org/apache/jmeter/control/CriticalSectionController.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/control/CriticalSectionController.java?rev=1611689&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/control/CriticalSectionController.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/control/CriticalSectionController.java Fri
Jul 18 16:13:18 2014
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.control;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.jmeter.samplers.Sampler;
+import org.apache.jmeter.testelement.TestStateListener;
+import org.apache.jmeter.testelement.ThreadListener;
+import org.apache.jmeter.testelement.property.StringProperty;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * This is a Critical Section Controller; it will execute the set of statements
+ * (samplers/controllers, etc) under named lock.
+ * <p>
+ * In a programming world - this is equivalent of :
+ * 
+ * <pre>
+ * try {
+ *          named_lock.lock();
+ *          statements ....
+ * } finally {
+ *          named_lock.unlock();
+ * }
+ * </pre>
+ * 
+ * In JMeter you may have :
+ * 
+ * <pre>
+ * Thread-Group (set to loop a number of times or indefinitely,
+ *    ... Samplers ... (e.g. Counter )
+ *    ... Other Controllers ....
+ *    ... CriticalSectionController ( lock name like "foobar" )
+ *       ... statements to perform when lock acquired
+ *       ...
+ *    ... Other Controllers /Samplers }
+ * </pre>
+ * 
+ * @since 2.12
+ */
+public class CriticalSectionController extends GenericController implements
+        ThreadListener, TestStateListener {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 4362876132435968088L;
+
+    private static final Logger logger = LoggingManager.getLoggerForClass();
+
+    private static final String LOCK_NAME = "CriticalSectionController.lockName"; //$NON-NLS-1$
+
+    private static final ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<String,
ReentrantLock>();
+
+    private transient ReentrantLock currentLock;
+
+    /**
+     * constructor
+     */
+    public CriticalSectionController() {
+        super();
+    }
+
+    /**
+     * constructor
+     */
+    public CriticalSectionController(String name) {
+        super();
+        this.setName(name);
+    }
+
+    /**
+     * Condition Accessor - this is gonna be any string value
+     */
+    public void setLockName(String name) {
+        setProperty(new StringProperty(LOCK_NAME, name));
+    }
+
+    /**
+     * Function for autocreate and get lock
+     * 
+     * @return named lock
+     */
+    private ReentrantLock getLock() {
+        ReentrantLock lock = lockMap.get(getLockName());
+        ReentrantLock prev = null;
+        if (lock != null) {
+            return lock;
+        }
+        lock = new ReentrantLock();
+        prev = lockMap.putIfAbsent(getLockName(), lock);
+        return prev == null ? lock : prev;
+    }
+
+    /**
+     * Lock name
+     */
+    public String getLockName() {
+        return getPropertyAsString(LOCK_NAME);
+    }
+
+    /**
+     * @see org.apache.jmeter.control.Controller#next()
+     */
+    @Override
+    public Sampler next() {
+        if (StringUtils.isEmpty(getLockName())) {
+            logger.warn("Empty lock name in Critical Section Controller:"
+                    + getName());
+            return super.next();
+        }
+        if (isFirst()) {
+            // Take the lock for first child element
+            long startTime = System.currentTimeMillis();
+            if (this.currentLock == null) {
+                this.currentLock = getLock();
+            }
+            this.currentLock.lock();
+            long endTime = System.currentTimeMillis();
+            if (logger.isDebugEnabled()) {
+                logger.debug(Thread.currentThread().getName()
+                        + " acquired lock:'" + getLockName()
+                        + "' in Critical Section Controller " + getName()
+                        + " in:" + (endTime - startTime) + " ms");
+            }
+        }
+        return super.next();
+    }
+
+    /**
+     * Called after execution of last child of the controller We release lock
+     * 
+     * @see org.apache.jmeter.control.GenericController#reInitialize()
+     */
+    @Override
+    protected void reInitialize() {
+        if (this.currentLock != null) {
+            if (currentLock.isHeldByCurrentThread()) {
+                this.currentLock.unlock();
+            }
+            this.currentLock = null;
+        }
+        super.reInitialize();
+    }
+
+    @Override
+    public void threadStarted() {
+        this.currentLock = null;
+    }
+
+    @Override
+    public void threadFinished() {
+        if (this.currentLock != null
+                && this.currentLock.isHeldByCurrentThread()) {
+            logger.warn("Lock " + getLockName() + " not released in:"
+                    + getName() + ", releasing in threadFinished");
+            this.currentLock.unlock();
+        }
+        this.currentLock = null;
+    }
+
+    @Override
+    public void testStarted() {
+        // NOOP
+    }
+
+    @Override
+    public void testStarted(String host) {
+        // NOOP
+    }
+
+    @Override
+    public void testEnded() {
+        lockMap.clear();
+    }
+
+    @Override
+    public void testEnded(String host) {
+        testEnded();
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/control/CriticalSectionController.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/control/gui/CriticalSectionControllerGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/control/gui/CriticalSectionControllerGui.java?rev=1611689&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/control/gui/CriticalSectionControllerGui.java
(added)
+++ jmeter/trunk/src/components/org/apache/jmeter/control/gui/CriticalSectionControllerGui.java
Fri Jul 18 16:13:18 2014
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.control.gui;
+
+import java.awt.BorderLayout;
+
+import javax.swing.Box;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.apache.jmeter.control.CriticalSectionController;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.util.JMeterUtils;
+
+/**
+ * The user interface for a controller which specifies that its subcomponents
+ * should be executed while a condition holds. This component can be used
+ * standalone or embedded into some other component.
+ * 
+ * @since 2.12
+ */
+public class CriticalSectionControllerGui extends AbstractControllerGui {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 7177285850634344095L;
+
+    /**
+     * A field allowing the user to specify the number of times the controller
+     * should loop.
+     */
+    private JTextField tfLockName;
+
+    /**
+     * Boolean indicating whether or not this component should display its name.
+     * If true, this is a standalone component. If false, this component is
+     * intended to be used as a subpanel for another component.
+     */
+    private boolean displayName = true;
+
+    /**
+     * Create a new LoopControlPanel as a standalone component.
+     */
+    public CriticalSectionControllerGui() {
+        this(true);
+    }
+
+    /**
+     * Create a new IfControllerPanel as either a standalone or an embedded
+     * component.
+     * 
+     * @param displayName
+     *            indicates whether or not this component should display its
+     *            name. If true, this is a standalone component. If false, this
+     *            component is intended to be used as a subpanel for another
+     *            component.
+     */
+    public CriticalSectionControllerGui(boolean displayName) {
+        this.displayName = displayName;
+        init();
+    }
+
+    /**
+     * A newly created component can be initialized with the contents of a Test
+     * Element object by calling this method. The component is responsible for
+     * querying the Test Element object for the relevant information to display
+     * in its GUI.
+     * 
+     * @param element
+     *            the TestElement to configure
+     */
+    @Override
+    public void configure(TestElement element) {
+        super.configure(element);
+        if (element instanceof CriticalSectionController) {
+            CriticalSectionController controller = (CriticalSectionController) element;
+            tfLockName.setText(controller.getLockName());
+        }
+
+    }
+
+    /**
+     * Implements JMeterGUIComponent.createTestElement()
+     */
+    @Override
+    public TestElement createTestElement() {
+        CriticalSectionController controller = new CriticalSectionController();
+        modifyTestElement(controller);
+        return controller;
+    }
+
+    /**
+     * Implements JMeterGUIComponent.modifyTestElement(TestElement)
+     */
+    @Override
+    public void modifyTestElement(TestElement controller) {
+        configureTestElement(controller);
+        if (controller instanceof CriticalSectionController) {
+            CriticalSectionController csController = (CriticalSectionController) controller;
+            csController.setLockName(tfLockName.getText());
+        }
+    }
+
+    /**
+     * Implements JMeterGUIComponent.clearGui
+     */
+    @Override
+    public void clearGui() {
+        super.clearGui();
+        tfLockName.setText("global_lock"); // $NON-NLS-1$
+    }
+
+    @Override
+    public String getLabelResource() {
+        return "critical_section_controller_title"; // $NON-NLS-1$
+    }
+
+    /**
+     * Initialize the GUI components and layout for this component.
+     */
+    private void init() {
+        // Standalone
+        if (displayName) {
+            setLayout(new BorderLayout(0, 5));
+            setBorder(makeBorder());
+            add(makeTitlePanel(), BorderLayout.NORTH);
+
+            JPanel mainPanel = new JPanel(new BorderLayout());
+            mainPanel.add(createConditionPanel(), BorderLayout.NORTH);
+            add(mainPanel, BorderLayout.CENTER);
+
+        } else {
+            // Embedded
+            setLayout(new BorderLayout());
+            add(createConditionPanel(), BorderLayout.NORTH);
+        }
+    }
+
+    /**
+     * Create a GUI panel containing the condition.
+     * 
+     * @return a GUI panel containing the condition components
+     */
+    private JPanel createConditionPanel() {
+        JPanel conditionPanel = new JPanel(new BorderLayout(5, 0));
+
+        // Condition LABEL
+        JLabel conditionLabel = new JLabel(
+                JMeterUtils.getResString("critical_section_controller_label")); // $NON-NLS-1$
+        conditionPanel.add(conditionLabel, BorderLayout.WEST);
+
+        // TEXT FIELD
+        tfLockName = new JTextField(""); // $NON-NLS-1$
+        conditionLabel.setLabelFor(tfLockName);
+        conditionPanel.add(tfLockName, BorderLayout.CENTER);
+
+        conditionPanel
+                .add(Box.createHorizontalStrut(conditionLabel
+                        .getPreferredSize().width
+                        + tfLockName.getPreferredSize().width),
+                        BorderLayout.NORTH);
+
+        return conditionPanel;
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/control/gui/CriticalSectionControllerGui.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1611689&r1=1611688&r2=1611689&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Fri Jul 18 16:13:18
2014
@@ -209,6 +209,8 @@ counter_config_title=Counter
 counter_per_user=Track counter independently for each user
 counter_reset_per_tg_iteration=Reset counter on each Thread Group Iteration
 countlim=Size limit
+critical_section_controller_label=Lock name
+critical_section_controller_title=Critical Section Controller
 csvread_file_file_name=CSV file to get values from | *alias
 cut=Cut
 cut_paste_function=Copy and paste function string

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1611689&r1=1611688&r2=1611689&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Fri Jul 18 16:13:18
2014
@@ -197,6 +197,8 @@ counter_config_title=Compteur
 counter_per_user=Suivre le compteur ind\u00E9pendamment pour chaque unit\u00E9 de test
 counter_reset_per_tg_iteration=R\u00E9initialiser le compteur \u00E0 chaque it\u00E9ration
du groupe d'unit\u00E9s
 countlim=Limiter le nombre d'\u00E9l\u00E9ments retourn\u00E9s \u00E0
+critical_section_controller_label=Nom du verrou
+critical_section_controller_title=Contr\u00F4leur section critique
 cssjquery_attribute=Attribut
 cssjquery_impl=Impl\u00E9mentation CSS/JQuery\:
 cssjquery_render_no_text=Les donn\u00E9es de r\u00E9ponse ne sont pas du texte.

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1611689&r1=1611688&r2=1611689&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml (original)
+++ jmeter/trunk/xdocs/changes.xml Fri Jul 18 16:13:18 2014
@@ -1,4 +1,4 @@
-<?xml version="1.0"?> 
+Crti<?xml version="1.0"?> 
 <!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -201,6 +201,7 @@ A workaround is to use a Java 7 update 4
 
 <h3>Controllers</h3>
 <ul>
+<li><bugzilla>56728</bugzilla> - New Critical Section Controller to serialize
blocks of a Test. Based partly on a patch contributed by Mikhail Epikhin(epihin-m at yandex.ru)</li>
 </ul>
 
 <h3>Listeners</h3>

Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1611689&r1=1611688&r2=1611689&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/component_reference.xml Fri Jul 18 16:13:18 2014
@@ -2518,6 +2518,17 @@ be saved under the Recording Controller.
 
 </component>
 
+<component name="Critical Section Controller" index="&sect-num;.2.17" width="420"
height="79" screenshot="logic-controller/critical-section-controller.png">
+<description>
+<p>The Critical Section Controller ensures that its children elements (samplers/controllers,
etc) will be executed 
+by only one thread as a named lock will be taken before executing children of controller.</p>
+
+</description>
+<properties>
+        <property name="Lock Name" required="Yes">Lock that will be taken by controller,
ensure you use different lock names for unrelated sections</property>
+</properties>
+
+</component>
 
 <a href="#">^</a>
 



Mime
View raw message