Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added extension-point for LockManager. Added option for specifying max value for version-number when using version-number strategy with optimistic locking. #505

Merged
merged 1 commit into from Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/main/java/org/datanucleus/ExecutionContextImpl.java
Expand Up @@ -352,13 +352,39 @@ protected Object initialValue()
pbrAtCommitHandler = new ReachabilityAtCommitHandler(this);
}

lockMgr = new LockManagerImpl(this);
lockMgr = createLockManager();

l2CacheObjectsToEvictUponRollback = null;

setLevel2Cache(true);
}

private LockManager createLockManager()
{
String lockManagerType = nucCtx.getConfiguration().getStringProperty(PropertyNames.PROPERTY_LOCKMANAGER_TYPE);
if (lockManagerType != null && !lockManagerType.isEmpty())
{
final Object tmpLocManager;
try
{
// Create an instance of the lock manager
tmpLocManager = nucCtx.getPluginManager().createExecutableExtension("org.datanucleus.lockmanager", "name", lockManagerType, "class-name",
new Class[]{ExecutionContext.class}, new Object[]{this});
}
catch (Exception e)
{
// Class name for this lockmanager plugin is not found!
throw new NucleusUserException("Failed to create requested lock manager: " + lockManagerType, e).setFatal();
}
if (tmpLocManager instanceof LockManager)
{
return (LockManager) tmpLocManager;
}
throw new NucleusUserException("Requested lock manager not found: " + lockManagerType).setFatal();
}
return new LockManagerImpl(this);
}

/**
* Method to close the context.
*/
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/datanucleus/PropertyNames.java
Expand Up @@ -252,4 +252,5 @@ public class PropertyNames
public static final String PROPERTY_QUERY_RESULTCACHE_VALIDATEOBJECTS = "datanucleus.query.resultcache.validateobjects";
public static final String PROPERTY_QUERY_RESULT_SIZE_METHOD = "datanucleus.query.resultsizemethod";
public static final String PROPERTY_QUERY_COMPILE_NAMED_QUERIES_AT_STARTUP = "datanucleus.query.compilenamedqueriesatstartup";
public static final String PROPERTY_LOCKMANAGER_TYPE = "datanucleus.lockmanager.type";
}
3 changes: 3 additions & 0 deletions src/main/java/org/datanucleus/metadata/MetaData.java
Expand Up @@ -112,6 +112,9 @@ private enum State
/** Class : initial value to use for this class for versioning (when using version-number strategy). */
public static final String EXTENSION_VERSION_NUMBER_INITIAL_VALUE = "version-initial-value";

/** Class : max value for version field before rolling over to initial value again (when using version-number strategy). */
public static final String EXTENSION_VERSION_NUMBER_MAX_VALUE = "version-max-value";

/** Member : name of type converter to use. */
public final static String EXTENSION_MEMBER_TYPE_CONVERTER_NAME = "type-converter-name";

Expand Down
16 changes: 12 additions & 4 deletions src/main/java/org/datanucleus/state/LockManagerImpl.java
Expand Up @@ -39,13 +39,13 @@
*/
public class LockManagerImpl implements LockManager
{
ExecutionContext ec;
protected final ExecutionContext ec;

/** Map of lock mode, keyed by the object identity. Utilised on a find operation. */
Map<Object, LockMode> requiredLockModesById = null;
private Map<Object, LockMode> requiredLockModesById = null;

/** Map of lock mode, keyed by StateManager. */
Map<DNStateManager, LockMode> lockModeBySM = null;
private Map<DNStateManager, LockMode> lockModeBySM = null;

public LockManagerImpl(ExecutionContext ec)
{
Expand Down Expand Up @@ -282,7 +282,15 @@ else if (java.time.Instant.class.isAssignableFrom(verMmd.getType()))
}
else if (versionStrategy == VersionStrategy.VERSION_NUMBER)
{
if (currentVersion == null)
// First check if a max-value is defined in version-meta-data
// and if so then check if we should roll over - back to initial value.
Integer maxValue = null;
if (vermd.hasExtension(MetaData.EXTENSION_VERSION_NUMBER_MAX_VALUE))
{
maxValue = Integer.valueOf(vermd.getValueForExtension(MetaData.EXTENSION_VERSION_NUMBER_MAX_VALUE));
}
if (currentVersion == null ||
(maxValue != null && currentVersion instanceof Number && ((Number)currentVersion).intValue() >= maxValue))
{
// Get the initial value from the VersionMetaData extension if provided, otherwise the global default (for the context)
Integer initValue = null;
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/plugin.xml
Expand Up @@ -51,6 +51,7 @@ Contributors:
<extension-point id="class_annotation_handler" name="Class Annotation Handler" schema="schema/class_annotation_handler.exsd"/>
<extension-point id="member_annotation_handler" name="Member Annotation Handler" schema="schema/member_annotation_handler.exsd"/>
<extension-point id="identifier_namingfactory" name="Identifier NamingFactory" schema="schema/identifier_namingfactory.exsd"/>
<extension-point id="lockmanager" name="Lock Manager" schema="schema/lockmanager.exsd"/>

<!-- XML METADATA ENTITY RESOLVERS -->
<extension point="org.datanucleus.metadata_entityresolver">
Expand Down
112 changes: 112 additions & 0 deletions src/main/resources/schema/lockmanager.exsd
@@ -0,0 +1,112 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="org.datanucleus">
<annotation>
<appInfo>
<meta.schema plugin="org.datanucleus" id="lockmanager" name="Lock Manager"/>
</appInfo>
<documentation>
[Enter description of this extension point.]
</documentation>
</annotation>

<element name="extension">
<complexType>
<sequence>
<element ref="lockmanager" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
<attribute name="point" type="string" use="required">
<annotation>
<documentation>

</documentation>
</annotation>
</attribute>
<attribute name="id" type="string">
<annotation>
<documentation>

</documentation>
</annotation>
</attribute>
<attribute name="name" type="string">
<annotation>
<documentation>

</documentation>
<appInfo>
<meta.attribute translatable="true"/>
</appInfo>
</annotation>
</attribute>
</complexType>
</element>

<element name="lockmanager">
<complexType>
<attribute name="name" type="string" use="required">
<annotation>
<documentation>

</documentation>
</annotation>
</attribute>
<attribute name="class-name" type="string" use="required">
<annotation>
<documentation>

</documentation>
<appInfo>
<meta.attribute kind="java" basedOn="org.datanucleus.state.LockManager"/>
</appInfo>
</annotation>
</attribute>
</complexType>
</element>

<annotation>
<appInfo>
<meta.section type="since"/>
</appInfo>
<documentation>
[Enter the first release in which this extension point appears.]
</documentation>
</annotation>

<annotation>
<appInfo>
<meta.section type="examples"/>
</appInfo>
<documentation>
[Enter extension point usage example here.]
</documentation>
</annotation>

<annotation>
<appInfo>
<meta.section type="apiInfo"/>
</appInfo>
<documentation>
[Enter API information here.]
</documentation>
</annotation>

<annotation>
<appInfo>
<meta.section type="implementation"/>
</appInfo>
<documentation>
[Enter information about supplied implementation of this extension point.]
</documentation>
</annotation>

<annotation>
<appInfo>
<meta.section type="copyright"/>
</appInfo>
<documentation>

</documentation>
</annotation>

</schema>