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

XWIKI-22782: Only save modified xobjects #3798

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.inject.Inject;
import javax.inject.Named;
Expand All @@ -29,6 +31,9 @@
import org.apache.commons.lang3.StringUtils;
import org.xwiki.component.annotation.Component;
import org.xwiki.configuration.ConfigurationSource;
import org.xwiki.model.EntityType;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.EntityReferenceResolver;

import com.xpn.xwiki.internal.XWikiCfgConfigurationSource;

Expand All @@ -46,6 +51,10 @@ public class HibernateConfiguration
@Named(XWikiCfgConfigurationSource.ROLEHINT)
private ConfigurationSource xwikiConfiguration;

@Inject
@Named("relative")
private EntityReferenceResolver<String> resolver;

private String path;

/**
Expand Down Expand Up @@ -164,4 +173,20 @@ public List<String> getIgnoredMigrations()
{
return getList("xwiki.store.migration.ignored");
}

/**
* @return the local references of the classes for which we should apply a save optimization (save only the modified
* ones)
* @since 17.1.0RC1
* @since 16.10.3
*/
public Set<EntityReference> getOptimizedXObjectClasses()
{
List<String> references =
this.xwikiConfiguration.getProperty("xwiki.store.hibernate.optimizedObjectSave.classes", List.class);

return references != null
? references.stream().map(r -> this.resolver.resolve(r, EntityType.DOCUMENT)).collect(Collectors.toSet())
: null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,6 @@ public PropertyInterface get(String name) throws XWikiException
public void safeput(String name, PropertyInterface property)
{
addField(name, property);
if (property instanceof BaseProperty) {
((BaseProperty) property).setObject(this);
((BaseProperty) property).setName(name);
}
}

@Override
Expand Down Expand Up @@ -537,8 +533,13 @@ public void addField(String name, PropertyInterface element)
{
this.fields.put(name, element);

if (element instanceof BaseElement) {
((BaseElement) element).setOwnerDocument(getOwnerDocument());
element.setName(name);
if (element instanceof BaseElement baseElement) {
baseElement.setOwnerDocument(getOwnerDocument());

if (element instanceof BaseProperty baseProperty) {
baseProperty.setObject(this);
}
}
}

Expand Down Expand Up @@ -647,6 +648,8 @@ public BaseCollection clone()
}
collection.setFields(cfields);

collection.setDirty(isDirty());

return collection;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Objects;

import javax.inject.Provider;

Expand All @@ -37,6 +38,7 @@
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.EntityReferenceSerializer;
import org.xwiki.stability.Unstable;
import org.xwiki.store.merge.MergeManager;
import org.xwiki.store.merge.MergeManagerResult;

Expand Down Expand Up @@ -101,7 +103,35 @@ public abstract class BaseElement<R extends EntityReference> implements ElementI
private EntityReferenceSerializer<String> localUidStringEntityReferenceSerializer;

private ContextualLocalizationManager localization;


private transient boolean dirty = true;

/**
* @return true of the element was modified (or created)
* @since 17.1.0RC1
* @since 16.10.3
*/
tmortagne marked this conversation as resolved.
Show resolved Hide resolved
@Unstable
public boolean isDirty()
{
return this.dirty;
}

/**
* @param dirty true of the element was modified (or created)
* @since 17.1.0RC1
* @since 16.10.3
*/
tmortagne marked this conversation as resolved.
Show resolved Hide resolved
@Unstable
public void setDirty(boolean dirty)
{
this.dirty = dirty;

if (dirty && this.ownerDocument != null) {
this.ownerDocument.setMetaDataDirty(true);
tmortagne marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* @return a merge manager instance.
* @since 11.8RC1
Expand Down Expand Up @@ -161,12 +191,16 @@ public String getName()
}

@Override
public void setDocumentReference(DocumentReference reference)
public void setDocumentReference(DocumentReference documentReference)
{
// If the name is already set then reset it since we're now using a reference
this.documentReference = reference;
this.name = null;
this.referenceCache = null;
if (!Objects.equals(documentReference, this.documentReference)) {
// If the name is already set then reset it since we're now using a reference
this.documentReference = documentReference;
this.name = null;
this.referenceCache = null;

setDirty(true);
}
}

/**
Expand All @@ -185,8 +219,12 @@ public void setName(String name)
throw new IllegalStateException("BaseElement#setName could not be called when a reference has been set.");
}

this.name = name;
this.referenceCache = null;
if (!StringUtils.equals(name, this.name)) {
this.name = name;
this.referenceCache = null;

setDirty(true);
}
}

public String getPrettyName()
Expand Down Expand Up @@ -349,6 +387,8 @@ public BaseElement clone()
}

element.setPrettyName(getPrettyName());

element.dirty = this.dirty;
} catch (Exception e) {
// This should not happen
element = null;
Expand Down Expand Up @@ -417,7 +457,13 @@ public boolean apply(ElementInterface newElement, boolean clean)
*/
public void setOwnerDocument(XWikiDocument ownerDocument)
{
this.ownerDocument = ownerDocument;
if (this.ownerDocument != ownerDocument) {
this.ownerDocument = ownerDocument;

if (this.ownerDocument != null && isDirty()) {
this.ownerDocument.setMetaDataDirty(true);
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
*/
package com.xpn.xwiki.objects;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -44,7 +43,7 @@
import com.xpn.xwiki.objects.classes.PropertyClass;
import com.xpn.xwiki.web.Utils;

public class BaseObject extends BaseCollection<BaseObjectReference> implements ObjectInterface, Serializable, Cloneable
public class BaseObject extends BaseCollection<BaseObjectReference> implements ObjectInterface, Cloneable
{
private static final long serialVersionUID = 1L;

Expand Down Expand Up @@ -201,6 +200,8 @@ public BaseObject clone()
// is expensive)
object.setGuid(this.guid);

object.setDirty(isDirty());

return object;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
*/
package com.xpn.xwiki.objects;

import java.io.Serializable;
import java.util.Objects;

import org.apache.commons.lang3.ObjectUtils;
Expand All @@ -42,8 +41,7 @@
*/
// TODO: shouldn't this be abstract? toFormString and toText
// will never work unless getValue is overriden
public class BaseProperty<R extends EntityReference> extends BaseElement<R>
implements PropertyInterface, Serializable, Cloneable
public class BaseProperty<R extends EntityReference> extends BaseElement<R> implements PropertyInterface, Cloneable
{
private static final long serialVersionUID = 1L;

Expand All @@ -54,11 +52,6 @@ public class BaseProperty<R extends EntityReference> extends BaseElement<R>

private long id;

/**
* Set to true if value is not the same as the database value.
*/
private boolean isValueDirty = true;

@Override
protected R createReference()
{
Expand All @@ -82,6 +75,10 @@ public BaseCollection getObject()
public void setObject(BaseCollection object)
{
this.object = object;

if (this.object != null && isDirty()) {
this.object.setDirty(true);
}
}

@Override
Expand Down Expand Up @@ -124,9 +121,13 @@ public long getId()
@Override
public void setId(long id)
{
// I hate this.. needed for hibernate to find the object
// when loading the collections..
this.id = id;
if (id != this.id) {
// I hate this.. needed for hibernate to find the object
// when loading the collections..
this.id = id;

setDirty(true);
}
}

@Override
Expand Down Expand Up @@ -155,11 +156,12 @@ public BaseProperty<R> clone()

cloneInternal(property);

property.isValueDirty = this.isValueDirty;
property.ownerDocument = this.ownerDocument;

property.setObject(getObject());

property.setDirty(isDirty());

return property;
}

Expand Down Expand Up @@ -347,10 +349,12 @@ public boolean apply(ElementInterface newProperty, boolean clean)
/**
* @return {@literal true} if the property value doesn't match the value in the database.
* @since 4.3M2
* @deprecated use {@link #isDirty()} instead
*/
@Deprecated(since = "17.1.0RC1")
public boolean isValueDirty()
{
return this.isValueDirty;
return isDirty();
}

/**
Expand All @@ -360,38 +364,29 @@ public boolean isValueDirty()
*/
protected void setValueDirty(Object newValue)
{
if (!this.isValueDirty && !Objects.equals(newValue, getValue())) {
if (!isDirty() && !Objects.equals(newValue, getValue())) {
setValueDirty(true);
}
}

/**
* @param valueDirty Indicate if the dirty flag should be set or cleared.
* @since 4.3M2
* @deprecated use {@link #setDirty(boolean)} instead
*/
@Deprecated(since = "17.1.0RC1")
public void setValueDirty(boolean valueDirty)
{
this.isValueDirty = valueDirty;
if (valueDirty && this.ownerDocument != null) {
this.ownerDocument.setMetaDataDirty(true);
}
setDirty(valueDirty);
}

/**
* Set the owner document of this base property.
*
* @param ownerDocument The owner document.
* @since 4.3M2
*/
@Override
public void setOwnerDocument(XWikiDocument ownerDocument)
public void setDirty(boolean dirty)
{
if (this.ownerDocument != ownerDocument) {
super.setOwnerDocument(ownerDocument);
super.setDirty(dirty);

if (ownerDocument != null && this.isValueDirty) {
ownerDocument.setMetaDataDirty(true);
}
if (dirty && this.object != null) {
this.object.setDirty(true);
}
}

Expand Down
Loading