diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c2ddf73..79c62f90 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 1.1.0
+
+* Restructured root to improve performance with IDs in entities
+
# 1.0.10
* Optimistic locking with @Version now possible
diff --git a/docs/antora.yml b/docs/antora.yml
index fe1e95a1..f0e594e0 100644
--- a/docs/antora.yml
+++ b/docs/antora.yml
@@ -1,14 +1,14 @@
name: ROOT
title: Spring-Data-Eclipse-Store
version: master
-display_version: '1.0.10'
+display_version: '2.0.0'
start_page: index.adoc
nav:
- modules/ROOT/nav.adoc
asciidoc:
attributes:
product-name: 'Spring-Data-Eclipse-Store'
- display-version: '1.0.10'
- maven-version: '1.0.10'
+ display-version: '2.0.0'
+ maven-version: '2.0.0'
page-editable: false
page-out-of-support: false
diff --git a/pom.xml b/pom.xml
index e405b61f..c04c8e6b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
software.xdev
spring-data-eclipse-store-root
- 1.0.11-SNAPSHOT
+ 2.0.0-SNAPSHOT
pom
diff --git a/spring-data-eclipse-store-benchmark/pom.xml b/spring-data-eclipse-store-benchmark/pom.xml
index 33d6683f..bc549fc2 100644
--- a/spring-data-eclipse-store-benchmark/pom.xml
+++ b/spring-data-eclipse-store-benchmark/pom.xml
@@ -5,11 +5,11 @@
software.xdev
spring-data-eclipse-store-root
- 1.0.11-SNAPSHOT
+ 2.0.0-SNAPSHOT
spring-data-eclipse-store-benchmark
- 1.0.11-SNAPSHOT
+ 2.0.0-SNAPSHOT
jar
2023
diff --git a/spring-data-eclipse-store-demo/pom.xml b/spring-data-eclipse-store-demo/pom.xml
index ef2a2612..8d9ffd2d 100644
--- a/spring-data-eclipse-store-demo/pom.xml
+++ b/spring-data-eclipse-store-demo/pom.xml
@@ -7,11 +7,11 @@
software.xdev
spring-data-eclipse-store-root
- 1.0.11-SNAPSHOT
+ 2.0.0-SNAPSHOT
spring-data-eclipse-store-demo
- 1.0.11-SNAPSHOT
+ 2.0.0-SNAPSHOT
jar
diff --git a/spring-data-eclipse-store-jpa/pom.xml b/spring-data-eclipse-store-jpa/pom.xml
index 57974811..c9cc4e6d 100644
--- a/spring-data-eclipse-store-jpa/pom.xml
+++ b/spring-data-eclipse-store-jpa/pom.xml
@@ -7,11 +7,11 @@
software.xdev
spring-data-eclipse-store-root
- 1.0.11-SNAPSHOT
+ 2.0.0-SNAPSHOT
spring-data-eclipse-store-jpa
- 1.0.11-SNAPSHOT
+ 2.0.0-SNAPSHOT
jar
2023
diff --git a/spring-data-eclipse-store/pom.xml b/spring-data-eclipse-store/pom.xml
index 8de55834..af423612 100644
--- a/spring-data-eclipse-store/pom.xml
+++ b/spring-data-eclipse-store/pom.xml
@@ -6,7 +6,7 @@
software.xdev
spring-data-eclipse-store
- 1.0.11-SNAPSHOT
+ 2.0.0-SNAPSHOT
jar
spring-data-eclipse-store
@@ -148,6 +148,22 @@
${org.eclipse.serializer.version}
+
+ software.xdev
+ micro-migration
+ 2.0.0
+
+
+ storage-embedded
+ org.eclipse.store
+
+
+ storage-embedded-configuration
+ org.eclipse.store
+
+
+
+
org.junit.jupiter
junit-jupiter-engine
diff --git a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/core/EntityListProvider.java b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/core/EntityListProvider.java
index f7a8c5fe..6114fef8 100644
--- a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/core/EntityListProvider.java
+++ b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/core/EntityListProvider.java
@@ -17,7 +17,7 @@
public interface EntityListProvider
{
- EntityProvider getEntityProvider(final Class clazz);
+ EntityProvider getEntityProvider(final Class clazz);
long getEntityCount(final Class clazz);
}
diff --git a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/core/EntityProvider.java b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/core/EntityProvider.java
index 7e60f0a7..8a8ff19f 100644
--- a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/core/EntityProvider.java
+++ b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/core/EntityProvider.java
@@ -18,23 +18,27 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import software.xdev.spring.data.eclipse.store.repository.root.EntityData;
-public class EntityProvider
+
+@SuppressWarnings("java:S119")
+public class EntityProvider
{
- private final List> identitySets = new ArrayList<>();
+ private final List> entityDataList = new ArrayList<>();
- public void addIdentitySet(final IdentitySet extends T> identitySet)
+ public void addEntityData(final EntityData extends T, ID> entityData)
{
- this.identitySets.add(identitySet);
+ this.entityDataList.add(entityData);
}
public Stream extends T> stream()
{
- return this.identitySets.stream().flatMap(Set::stream);
+ return this.entityDataList.stream().map(EntityData::getEntities).flatMap(Set::stream);
}
public Collection toCollection()
@@ -51,4 +55,13 @@ public long size()
{
return this.stream().count();
}
+
+ public Optional findAnyEntityWithId(final ID id)
+ {
+ return (Optional)this.entityDataList
+ .stream()
+ .map(entityData -> entityData.getEntitiesById().get(id))
+ .filter(e -> e != null)
+ .findAny();
+ }
}
diff --git a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/exceptions/InvalidRootException.java b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/exceptions/InvalidRootException.java
new file mode 100644
index 00000000..421f4bb0
--- /dev/null
+++ b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/exceptions/InvalidRootException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright © 2024 XDEV Software (https://xdev.software)
+ *
+ * Licensed 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 software.xdev.spring.data.eclipse.store.exceptions;
+
+public class InvalidRootException extends RuntimeException
+{
+ public InvalidRootException(final String message)
+ {
+ super(message);
+ }
+}
diff --git a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/importer/EclipseStoreDataImporter.java b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/importer/EclipseStoreDataImporter.java
index 823df08b..ffc73864 100644
--- a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/importer/EclipseStoreDataImporter.java
+++ b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/importer/EclipseStoreDataImporter.java
@@ -34,8 +34,8 @@
import software.xdev.spring.data.eclipse.store.repository.SupportedChecker;
import software.xdev.spring.data.eclipse.store.repository.config.EclipseStoreClientConfiguration;
import software.xdev.spring.data.eclipse.store.repository.support.SimpleEclipseStoreRepository;
-import software.xdev.spring.data.eclipse.store.repository.support.copier.id.IdManager;
import software.xdev.spring.data.eclipse.store.repository.support.copier.working.RecursiveWorkingCopier;
+import software.xdev.spring.data.eclipse.store.repository.support.id.IdManager;
import software.xdev.spring.data.eclipse.store.transactions.EclipseStoreTransactionManager;
diff --git a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/EclipseStoreMigrator.java b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/EclipseStoreMigrator.java
new file mode 100644
index 00000000..84b0533f
--- /dev/null
+++ b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/EclipseStoreMigrator.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2024 XDEV Software (https://xdev.software)
+ *
+ * Licensed 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 software.xdev.spring.data.eclipse.store.repository;
+
+import java.util.TreeSet;
+
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
+
+import software.xdev.micromigration.eclipsestore.MigrationManager;
+import software.xdev.micromigration.migrater.reflection.ReflectiveMigrater;
+import software.xdev.micromigration.scripts.VersionAgnosticMigrationScript;
+import software.xdev.micromigration.version.MigrationVersion;
+import software.xdev.spring.data.eclipse.store.repository.root.VersionedRoot;
+import software.xdev.spring.data.eclipse.store.repository.root.update.scripts.v2_0_0_InitalizeVersioning;
+
+
+public final class EclipseStoreMigrator
+{
+ public static final Class> FIRST_UPDATE_SCRIPT = v2_0_0_InitalizeVersioning.class;
+
+ private EclipseStoreMigrator()
+ {
+ }
+
+ public static void migrate(final VersionedRoot versionedRoot, final EmbeddedStorageManager storageManager)
+ {
+ final ReflectiveMigrater migrater =
+ new ReflectiveMigrater(FIRST_UPDATE_SCRIPT.getPackageName());
+ new MigrationManager(versionedRoot, migrater, storageManager)
+ .migrate(versionedRoot);
+ }
+
+ public static MigrationVersion getLatestVersion()
+ {
+ final ReflectiveMigrater migrater =
+ new ReflectiveMigrater(FIRST_UPDATE_SCRIPT.getPackageName());
+ final TreeSet> sortedScripts = migrater.getSortedScripts();
+ return sortedScripts.isEmpty() ? new MigrationVersion(0, 0, 0) : sortedScripts.last().getTargetVersion();
+ }
+}
diff --git a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/EclipseStoreStorage.java b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/EclipseStoreStorage.java
index bfd86018..c5b7c1f8 100644
--- a/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/EclipseStoreStorage.java
+++ b/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/EclipseStoreStorage.java
@@ -18,7 +18,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -27,29 +26,33 @@
import org.eclipse.serializer.persistence.types.Storer;
import org.eclipse.serializer.reference.ObjectSwizzling;
import org.eclipse.store.storage.embedded.types.EmbeddedStorageFoundation;
+import org.eclipse.store.storage.embedded.types.EmbeddedStorageManager;
import org.eclipse.store.storage.types.StorageManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.xdev.spring.data.eclipse.store.core.EntityListProvider;
import software.xdev.spring.data.eclipse.store.core.EntityProvider;
-import software.xdev.spring.data.eclipse.store.core.IdentitySet;
import software.xdev.spring.data.eclipse.store.exceptions.AlreadyRegisteredException;
+import software.xdev.spring.data.eclipse.store.exceptions.InvalidRootException;
import software.xdev.spring.data.eclipse.store.repository.config.EclipseStoreClientConfiguration;
import software.xdev.spring.data.eclipse.store.repository.config.EclipseStoreStorageFoundationProvider;
+import software.xdev.spring.data.eclipse.store.repository.root.EntityData;
+import software.xdev.spring.data.eclipse.store.repository.root.VersionedRoot;
import software.xdev.spring.data.eclipse.store.repository.support.SimpleEclipseStoreRepository;
import software.xdev.spring.data.eclipse.store.repository.support.concurrency.ReadWriteLock;
import software.xdev.spring.data.eclipse.store.repository.support.concurrency.ReentrantJavaReadWriteLock;
-import software.xdev.spring.data.eclipse.store.repository.support.copier.id.IdManager;
-import software.xdev.spring.data.eclipse.store.repository.support.copier.id.IdManagerProvider;
-import software.xdev.spring.data.eclipse.store.repository.support.copier.id.IdSetter;
import software.xdev.spring.data.eclipse.store.repository.support.copier.version.EntityVersionIncrementer;
import software.xdev.spring.data.eclipse.store.repository.support.copier.version.VersionManager;
import software.xdev.spring.data.eclipse.store.repository.support.copier.version.VersionManagerProvider;
+import software.xdev.spring.data.eclipse.store.repository.support.id.IdManager;
+import software.xdev.spring.data.eclipse.store.repository.support.id.IdManagerProvider;
+import software.xdev.spring.data.eclipse.store.repository.support.id.IdSetter;
import software.xdev.spring.data.eclipse.store.repository.support.reposyncer.RepositorySynchronizer;
import software.xdev.spring.data.eclipse.store.repository.support.reposyncer.SimpleRepositorySynchronizer;
+@SuppressWarnings("java:S119")
public class EclipseStoreStorage
implements EntityListProvider, IdManagerProvider, VersionManagerProvider, PersistableChecker, ObjectSwizzling
{
@@ -68,8 +71,8 @@ public class EclipseStoreStorage
private final EclipseStoreStorageFoundationProvider foundationProvider;
private EntitySetCollector entitySetCollector;
private PersistableChecker persistenceChecker;
- private StorageManager storageManager;
- private Root root;
+ private EmbeddedStorageManager storageManager;
+ private VersionedRoot root;
private final WorkingCopyRegistry registry = new WorkingCopyRegistry();
private final ReadWriteLock readWriteLock = new ReentrantJavaReadWriteLock();
@@ -95,24 +98,55 @@ private synchronized void ensureEntitiesInRoot()
{
if(this.storageManager == null)
{
- LOG.info("Starting storage...");
- this.root = new Root();
final EmbeddedStorageFoundation> embeddedStorageFoundation =
- this.foundationProvider.createEmbeddedStorageFoundation();
- embeddedStorageFoundation.registerTypeHandler(BinaryHandlerImmutableCollectionsSet12.New());
- embeddedStorageFoundation.registerTypeHandler(BinaryHandlerImmutableCollectionsList12.New());
- this.storageManager = embeddedStorageFoundation.start(this.root);
+ this.startStorageManager();
this.persistenceChecker = new RelayedPersistenceChecker(embeddedStorageFoundation);
this.initRoot();
- final Integer entitySum =
- this.root.getEntityLists().values().stream().map(IdentitySet::size).reduce(0, Integer::sum);
LOG.info(
"Storage started with {} entity lists and {} entities.",
- this.root.getEntityLists().size(),
- entitySum);
+ this.root.getCurrentRootData().getEntityTypesCount(),
+ this.root.getCurrentRootData().getEntityCount()
+ );
+ EclipseStoreMigrator.migrate(this.root, this.storageManager);
}
}
+ private EmbeddedStorageFoundation> startStorageManager()
+ {
+ LOG.info("Starting storage...");
+ final EmbeddedStorageFoundation> embeddedStorageFoundation =
+ this.foundationProvider.createEmbeddedStorageFoundation();
+ embeddedStorageFoundation.registerTypeHandler(BinaryHandlerImmutableCollectionsSet12.New());
+ embeddedStorageFoundation.registerTypeHandler(BinaryHandlerImmutableCollectionsList12.New());
+ final EmbeddedStorageManager embeddedStorageManager = embeddedStorageFoundation.start();
+ if(embeddedStorageManager.root() != null)
+ {
+ if(embeddedStorageManager.root() instanceof final Root oldRoot)
+ {
+ embeddedStorageManager.setRoot(new VersionedRoot(oldRoot));
+ embeddedStorageManager.storeRoot();
+ }
+ else if(!(embeddedStorageManager.root() instanceof VersionedRoot))
+ {
+ throw new InvalidRootException(
+ "Root object of type %s is invalid."
+ .formatted(embeddedStorageManager.root()
+ .getClass()
+ .getName()
+ )
+ );
+ }
+ }
+ else
+ {
+ embeddedStorageManager.setRoot(new VersionedRoot());
+ embeddedStorageManager.storeRoot();
+ }
+ this.root = (VersionedRoot)embeddedStorageManager.root();
+ this.storageManager = embeddedStorageManager;
+ return embeddedStorageFoundation;
+ }
+
public SimpleEclipseStoreRepository getRepository(final Class entityClass)
{
return (SimpleEclipseStoreRepository)this.entityClassToRepository.get(entityClass);
@@ -125,28 +159,36 @@ private void initRoot()
LOG.debug("Initializing entity lists...");
}
this.repositorySynchronizer =
- new SimpleRepositorySynchronizer(this.root);
+ new SimpleRepositorySynchronizer(this.root.getCurrentRootData());
boolean entityListMustGetStored = false;
for(final Class> entityClass : this.entityClassToRepository.keySet())
{
- if(this.root.getEntityList(entityClass) == null)
+ if(this.root.getCurrentRootData().getEntityData(entityClass) == null)
{
- this.root.createNewEntityList(entityClass);
+ this.createNewEntityList(entityClass);
entityListMustGetStored = true;
}
}
if(entityListMustGetStored)
{
- this.storageManager.store(this.root.getEntityLists());
+ this.storageManager.store(this.root.getCurrentRootData().getEntityListsToStore());
}
this.entitySetCollector =
- new EntitySetCollector(this.root::getEntityList, this.entityClassToRepository.keySet());
+ new EntitySetCollector(
+ this.root.getCurrentRootData()::getEntityData,
+ this.entityClassToRepository.keySet());
if(LOG.isDebugEnabled())
{
LOG.debug("Done initializing entity lists.");
}
}
+ private void createNewEntityList(final Class entityClass)
+ {
+ final IdManager idManager = this.ensureIdManager(entityClass);
+ this.root.getCurrentRootData().createNewEntityList(entityClass, idManager::getId);
+ }
+
public synchronized void registerEntity(
final Class classToRegister,
final SimpleEclipseStoreRepository repository)
@@ -165,16 +207,16 @@ public synchronized void registerEntity(
}
}
- private IdentitySet getEntityList(final Class clazz)
+ private EntityData getEntityData(final Class clazz)
{
this.ensureEntitiesInRoot();
return this.readWriteLock.read(
- () -> this.root.getEntityList(clazz)
+ () -> this.root.getCurrentRootData().getEntityData(clazz)
);
}
@Override
- public EntityProvider getEntityProvider(final Class clazz)
+ public EntityProvider getEntityProvider(final Class clazz)
{
this.ensureEntitiesInRoot();
return this.entitySetCollector.getRelatedIdentitySets(clazz);
@@ -188,8 +230,8 @@ public long getEntityCount(final Class clazz)
return this.readWriteLock.read(
() ->
{
- final IdentitySet entityList = this.root.getEntityList(clazz);
- return entityList == null ? 0 : entityList.size();
+ final EntityData entityData = this.root.getCurrentRootData().getEntityData(clazz);
+ return entityData == null ? 0 : entityData.getEntityCount();
}
);
}
@@ -224,35 +266,32 @@ public void store(
/**
* Also collects the object-list to store, if necessary.
*/
- private Collection