eXo Platform 3.5

## Chapter 24. LockManager configuration

## Introduction

What LockManager does?

In general, LockManager stores Lock objects, so it can give a Lock object or can release it, etc.

Also, LockManager is responsible for removing Locks that live too long. This parameter may be configured with "time-out" property.

JCR provides two basic implementations of LockManager:

- `org.exoplatform.services.jcr.impl.core.lock.LockManagerImpl`;

- `org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl`;

In this article, we will mostly mention about CacheableLockManagerImpl.

You can enable LockManager by adding lock-manager-configuration to workspace-configuration.

For example:

    <workspace name="ws">

       ...

       <lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl">

          <properties>

             <property name="time-out" value="15m" />

             ...

          </properties>

       </lock-manager>

       ...

    </workspace>

## LockManagerImpl

LockManagerImpl is a simple implementation of LockManager, and also faster than CacheableLockManager. It stores Lock objects in HashMap and may also persist Locks if LockPersister is configured. LockManagerImpl does not support replication in any way.

See more about LockManager Configuration at here.

## CacheableLockManagerImpl

CacheableLockManagerImpl stores Lock objects in JBoss-cache, so Locks are replicable and affect on cluster, not only a single node. Also, JBoss-cache has JDBCCacheLoader, so Locks will be stored to the database.

Both of the implementations support to remove Expired Locks. LockRemover separates threads, that periodically ask LockManager to remove Locks that live so long. So, the timeout for LockRemover may be set as follows, the default value is 30m.

    <properties>

       <property name="time-out" value="10m" />

       ...

    </properties>

### Configuration

Replication requirements are the same for Cache.

You can see a full JCR configuration example at here.

Common tips:

- `clusterName` ("jbosscache-cluster-name") must be unique;

- `cache.jdbc.table.name` must be unique per datasource;

- `cache.jdbc.fqn.type` and cache.jdbc.node.type must be configured according to used database;

There are a few ways to configure CacheableLockManagerImpl, and all of them configure JBoss-cache and JDBCCacheLoader.

See http://community.jboss.org/wiki/JBossCacheJDBCCacheLoader

### Simple JbossCache Configuration

The first one is putting JbossCache configuraion file path to CacheableLockManagerImpl.

### Note

This configuration is not so good as you think. Because the repository may contain many workspaces, and each workspace must contain LockManager configuration, and LockManager configuration may contain the JbossCache config file. So, the total configuration will grow up. But it is useful if we want to have a single LockManager with a special configuration.

Configuration is as follows:

    <lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl">

       <properties>

         <property name="time-out" value="15m" />

         <property name="jbosscache-configuration" value="conf/standalone/cluster/test-jbosscache-lock-config.xml" />

       </properties>

    </lock-manager>

`test-jbosscache-lock-config.xml`

    <?xml version="1.0" encoding="UTF-8"?>

    <jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.2">

     <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="20000" />

     <clustering mode="replication" clusterName="JBoss-Cache-Lock-Cluster_Name">

      <stateRetrieval timeout="20000" fetchInMemoryState="false" nonBlocking="true" />

      <jgroupsConfig>

       <TCP bind_addr="127.0.0.1" start_port="9800" loopback="true" recv_buf_size="20000000" send_buf_size="640000" discard_incompatible_packets="true"

        max_bundle_size="64000" max_bundle_timeout="30" use_incoming_packet_handler="true" enable_bundling="false" use_send_queues="false" sock_conn_timeout="300"

        skip_suspected_members="true" use_concurrent_stack="true" thread_pool.enabled="true" thread_pool.min_threads="1" thread_pool.max_threads="25"

        thread_pool.keep_alive_time="5000" thread_pool.queue_enabled="false" thread_pool.queue_max_size="100" thread_pool.rejection_policy="run"

        oob_thread_pool.enabled="true" oob_thread_pool.min_threads="1" oob_thread_pool.max_threads="8" oob_thread_pool.keep_alive_time="5000"

        oob_thread_pool.queue_enabled="false" oob_thread_pool.queue_max_size="100" oob_thread_pool.rejection_policy="run" />

       <MPING timeout="2000" num_initial_members="2" mcast_port="34540" bind_addr="127.0.0.1" mcast_addr="224.0.0.1" />

       <MERGE2 max_interval="30000" min_interval="10000" />

       <FD_SOCK />

       <FD max_tries="5" shun="true" timeout="10000" />

       <VERIFY_SUSPECT timeout="1500" />

       <pbcast.NAKACK discard_delivered_msgs="true" gc_lag="0" retransmit_timeout="300,600,1200,2400,4800" use_mcast_xmit="false" />

       <UNICAST timeout="300,600,1200,2400,3600" />

       <pbcast.STABLE desired_avg_gossip="50000" max_bytes="400000" stability_delay="1000" />

       <pbcast.GMS join_timeout="5000" print_local_addr="true" shun="false" view_ack_collection_timeout="5000" view_bundling="true" />

       <FRAG2 frag_size="60000" />

       <pbcast.STREAMING_STATE_TRANSFER />

      <pbcast.FLUSH timeout="0" />

      </jgroupsConfig

      <sync />

     </clustering>

     <loaders passivation="false" shared="true">

      <preload>

       <node fqn="/" />

      </preload>

      <loader class="org.jboss.cache.loader.JDBCCacheLoader" async="false" fetchPersistentState="false" ignoreModifications="false" purgeOnStartup="false">

       <properties>

        cache.jdbc.table.name=jcrlocks_ws

        cache.jdbc.table.create=true

        cache.jdbc.table.drop=false

        cache.jdbc.table.primarykey=jcrlocks_ws_pk

        cache.jdbc.fqn.column=fqn

        cache.jdbc.fqn.type=VARCHAR(512)

        cache.jdbc.node.column=node

        cache.jdbc.node.type=<BLOB>

        cache.jdbc.parent.column=parent

        cache.jdbc.datasource=jdbcjcr

       </properties>

      </loader>

     </loaders>

    </jbosscache>

Configuration requirements:

- <clustering mode="replication" clusterName="JBoss-Cache-Lock-Cluster_Name"> - the cluster name must be unique;

- `cache.jdbc.table.name` must be unique per datasource;

- `cache.jdbc.node.type` and `cache.jdbc.fqn.type` must be configured according to using the database. See Data Types in Different Databases .

### Template JBossCache Configuration

The second one is using the template JBoss-cache configuration for all LockManagers.

Lock template configuration

`test-jbosscache-lock.xml`

    <?xml version="1.0" encoding="UTF-8"?>

    <jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1">

       <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false"

          lockAcquisitionTimeout="20000" />

       <clustering mode="replication" clusterName="${jbosscache-cluster-name}">

          <stateRetrieval timeout="20000" fetchInMemoryState="false" />

          <jgroupsConfig multiplexerStack="jcr.stack" />

          <sync />

       </clustering>

       <loaders passivation="false" shared="true">

          <!-- All the data of the JCR locks needs to be loaded at startup -->

          <preload>

             <node fqn="/" />

          </preload>

          <!--

          For another cache-loader class you should use another template with

          cache-loader specific parameters

          ->

          <loader class="org.jboss.cache.loader.JDBCCacheLoader" async=q"false" fetchPersistentState="false"

             ignoreModifications="false" purgeOnStartup="false">

             <properties>

                cache.jdbc.table.name=${jbosscache-cl-cache.jdbc.table.name}

                cache.jdbc.table.create=${jbosscache-cl-cache.jdbc.table.create}

                cache.jdbc.table.drop=${jbosscache-cl-cache.jdbc.table.drop}

                cache.jdbc.table.primarykey=${jbosscache-cl-cache.jdbc.table.primarykey}

                cache.jdbc.fqn.column=${jbosscache-cl-cache.jdbc.fqn.column}

                cache.jdbc.fqn.type=${jbosscache-cl-cache.jdbc.fqn.type}

                cache.jdbc.node.column=${jbosscache-cl-cache.jdbc.node.column}

                cache.jdbc.node.type=${jbosscache-cl-cache.jdbc.node.type}

                cache.jdbc.parent.column=${jbosscache-cl-cache.jdbc.parent.column}

                cache.jdbc.datasource=${jbosscache-cl-cache.jdbc.datasource}

             </properties>

          </loader>

       </loaders>

    </jbosscache>

As you see, all configurable parameters are filled by templates and will be replaced by LockManagers configuration parameters:

    <lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl">

       <properties>

          <property name="time-out" value="15m" />

          <property name="jbosscache-configuration" value="test-jbosscache-lock.xml" />

          <property name="jgroups-configuration" value="udp-mux.xml" />

          <property name="jgroups-multiplexer-stack" value="true" />

          <property name="jbosscache-cluster-name" value="JCR-cluster-locks-ws" />

          <property name="jbosscache-cl-cache.jdbc.table.name" value="jcrlocks_ws" />

          <property name="jbosscache-cl-cache.jdbc.table.create" value="true" />

          <property name="jbosscache-cl-cache.jdbc.table.drop" value="false" />

          <property name="jbosscache-cl-cache.jdbc.table.primarykey" value="jcrlocks_ws_pk" />

          <property name="jbosscache-cl-cache.jdbc.fqn.column" value="fqn" />

          <property name="jbosscache-cl-cache.jdbc.fqn.type" value="AUTO"/>

          <property name="jbosscache-cl-cache.jdbc.node.column" value="node" />

          <property name="jbosscache-cl-cache.jdbc.node.type" value="AUTO"/>

          <property name="jbosscache-cl-cache.jdbc.parent.column" value="parent" />

          <property name="jbosscache-cl-cache.jdbc.datasource" value="jdbcjcr" />

       </properties>

    </lock-manager>

Configuration requirements:

- `jbosscache-cl-cache.jdbc.fqn.column` and `jbosscache-cl-cache.jdbc.node.type` is the same as cache.jdbc.fqn.type and cache.jdbc.node.type in JBoss-Cache configuration. You can set those data types according to database type (See Data Types in Different Databases) or set it as AUTO (or do not set at all) and data type will be detected automatically.

- As you see, jgroups-configuration is moved to separate the configuration file - udp-mux.xml. In this case, the udp-mux.xml file is a common JGroup configuration for all components (QueryHandler, Cache, LockManager), but we can still create our own configuration.

`our-udp-mux.xml`

    <protocol_stacks>

       <stack name="jcr.stack">

          <config>

             <UDP mcast_addr="228.10.10.10" mcast_port="45588" tos="8" ucast_recv_buf_size="20000000"

                ucast_send_buf_size="640000" mcast_recv_buf_size="25000000" mcast_send_buf_size="640000" loopback="false"

                discard_incompatible_packets="true" max_bundle_size="64000" max_bundle_timeout="30"

                use_incoming_packet_handler="true" ip_ttl="2" enable_bundling="true" enable_diagnostics="true"

                thread_naming_pattern="cl" use_concurrent_stack="true" thread_pool.enabled="true" thread_pool.min_threads="2"

                thread_pool.max_threads="8" thread_pool.keep_alive_time="5000" thread_pool.queue_enabled="true"

                thread_pool.queue_max_size="1000" thread_pool.rejection_policy="discard" oob_thread_pool.enabled="true"

                oob_thread_pool.min_threads="1" oob_thread_pool.max_threads="8" oob_thread_pool.keep_alive_time="5000"

                oob_thread_pool.queue_enabled="false" oob_thread_pool.queue_max_size="100" oob_thread_pool.rejection_policy="Run" />

             <PING timeout="2000" num_initial_members="3" />

             <MERGE2 max_interval="30000" min_interval="10000" />

             <FD_SOCK />

             <FD timeout="10000" max_tries="5" shun="true" />

             <VERIFY_SUSPECT timeout="1500" />

             <BARRIER />

             <pbcast.NAKACK use_stats_for_retransmission="false" exponential_backoff="150" use_mcast_xmit="true"

                gc_lag="0" retransmit_timeout="50,300,600,1200" discard_delivered_msgs="true" />

             <UNICAST timeout="300,600,1200" />

             <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000" max_bytes="1000000" />

             <VIEW_SYNC avg_send_interval="60000" />

             <pbcast.GMS print_local_addr="true" join_timeout="3000" shun="false" view_bundling="true" />

             <FC max_credits="500000" min_threshold="0.20" />

             <FRAG2 frag_size="60000" />

             <!--pbcast.STREAMING_STATE_TRANSFER /-->

             <pbcast.STATE_TRANSFER />

             <!-- pbcast.FLUSH  /-->

          </config>

       </stack>

    </protocol_stacks>

### Data Types in Different Databases

DataBase name | Node data type | FQN data type
--- | --- | ---
default | BLOB | VARCHAR(512)
HSSQL | OBJECT | VARCHAR(512)
MySQL | LONGBLOB | VARCHAR(512)
ORACLE | BLOB | VARCHAR2(512)
PostgreSQL | bytea | VARCHAR(512)
MSSQL | VARBINARY(MAX) | VARCHAR(512)
DB2 | BLOB | VARCHAR(512)
Sybase | IMAGE | VARCHAR(512)
Ingres | long byte | VARCHAR(512)

### Lock migration from 1.12.x

There are 3 choices:

I. When new Shareable Cache feature is not going to be used and all locks should be kept after migration.

- Ensure that the same lock tables used in configuration;

- Start the server;

II. When new Shareable Cache feature is not going to be used and all locks should be removed after migration.

- Ensure that the same lock tables used in configuration;

- Start the sever WITH system property -Dorg.exoplatform.jcr.locks.force.remove=true;

- Stop the server;

- Start the server (WITHOUT system property -Dorg.exoplatform.jcr.locks.force.remove);

III. When new Shareable Cache feature will be used (in this case all locks are removed after migration).

- Start the sever WITH system property -Dorg.exoplatform.jcr.locks.force.remove=true;

- Stop the server;

- Start the server (WITHOUT system property -Dorg.exoplatform.jcr.locks.force.remove);

- (Not mandatory) manually remove old tables for lock;