com.jetbrains.teamsys.dnq.database.TransientEntityStoreImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dnq-transient-store Show documentation
Show all versions of dnq-transient-store Show documentation
Data definition and queries Kotlin DSL over Xodus
/**
* Copyright 2006 - 2017 JetBrains s.r.o.
*
* 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 com.jetbrains.teamsys.dnq.database;
import jetbrains.exodus.core.dataStructures.StablePriorityQueue;
import jetbrains.exodus.core.dataStructures.hash.HashSet;
import jetbrains.exodus.core.execution.locks.Latch;
import jetbrains.exodus.database.*;
import jetbrains.exodus.entitystore.*;
import jetbrains.exodus.env.EnvironmentConfig;
import jetbrains.exodus.query.QueryEngine;
import jetbrains.exodus.query.metadata.ModelMetaData;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Vadim.Gurov
*/
public class TransientEntityStoreImpl implements TransientEntityStore {
private static final Logger logger = LoggerFactory.getLogger(TransientEntityStoreImpl.class);
private EntityStore persistentStore;
private QueryEngine queryEngine;
private ModelMetaData modelMetaData;
private IEventsMultiplexer eventsMultiplexer;
private final Set sessions =
Collections.newSetFromMap(new ConcurrentHashMap(200));
private final ThreadLocal currentSession = new ThreadLocal();
private final StablePriorityQueue listeners = new StablePriorityQueue();
private volatile boolean open = true;
private boolean closed = false;
private final Latch enumContainersLock = Latch.create();
private final Set initedContainers = new HashSet(10);
private final Map enumCache = new ConcurrentHashMap();
private final Map persistentClassInstanceCache = new ConcurrentHashMap();
private final Map persistentClassInstances = new ConcurrentHashMap();
final ReentrantLock flushLock = new ReentrantLock(true); // fair flushLock
public TransientEntityStoreImpl() {
if (logger.isTraceEnabled()) {
logger.trace("TransientEntityStoreImpl constructor called.");
}
}
public EntityStore getPersistentStore() {
return persistentStore;
}
public QueryEngine getQueryEngine() {
return queryEngine;
}
public IEventsMultiplexer getEventsMultiplexer() {
return eventsMultiplexer;
}
public void setEventsMultiplexer(IEventsMultiplexer eventsMultiplexer) {
this.eventsMultiplexer = eventsMultiplexer;
}
/**
* Must be injected.
*
* @param persistentStore persistent entity store.
*/
@SuppressWarnings({"UnusedDeclaration"})
public void setPersistentStore(EntityStore persistentStore) {
final EnvironmentConfig ec = ((PersistentEntityStore) persistentStore).getEnvironment().getEnvironmentConfig();
if (ec.getEnvTxnDowngradeAfterFlush() == EnvironmentConfig.DEFAULT.getEnvTxnDowngradeAfterFlush()) {
ec.setEnvTxnDowngradeAfterFlush(false);
}
ec.setEnvTxnReplayMaxCount(Integer.MAX_VALUE);
ec.setEnvTxnReplayTimeout(Long.MAX_VALUE);
ec.setGcUseExclusiveTransaction(true);
this.persistentStore = persistentStore;
}
/**
* Must be injected.
*
* @param queryEngine query engine.
*/
@SuppressWarnings({"UnusedDeclaration"})
public void setQueryEngine(QueryEngine queryEngine) {
this.queryEngine = queryEngine;
}
@NotNull
public String getName() {
return "transient store";
}
@NotNull
public String getLocation() {
throw new UnsupportedOperationException("Not supported by transient store.");
}
@NotNull
@Override
public StoreTransaction beginTransaction() {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public StoreTransaction beginExclusiveTransaction() {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public TransientStoreSession beginReadonlyTransaction() {
return registerStoreSession(new TransientSessionImpl(this, true));
}
@Nullable
@Override
public StoreTransaction getCurrentTransaction() {
throw new UnsupportedOperationException();
}
public TransientStoreSession beginSession() {
assertOpen();
if (logger.isDebugEnabled()) {
logger.debug("Begin new session");
}
TransientStoreSession currentSession = this.currentSession.get();
if (currentSession != null) {
logger.debug("Return session already associated with the current thread " + currentSession);
return currentSession;
}
return registerStoreSession(new TransientSessionImpl(this, false));
}
public void resumeSession(TransientStoreSession session) {
if (session != null) {
assertOpen();
TransientStoreSession current = currentSession.get();
if (current != null) {
if (current != session) {
throw new IllegalStateException("Another open transient session already associated with current thread.");
}
}
currentSession.set(session);
}
}
public void setModelMetaData(final ModelMetaData modelMetaData) {
this.modelMetaData = modelMetaData;
}
@Nullable
public ModelMetaData getModelMetaData() {
return modelMetaData;
}
/**
* It's guaranteed that current thread session is Open, if exists
*
* @return current thread session
*/
@Nullable
public TransientStoreSession getThreadSession() {
return currentSession.get();
}
@Override
public boolean isOpen() {
return open;
}
public void close() {
open = false;
eventsMultiplexer.onClose(this);
logger.info("Close transient store.");
closed = true;
int sessionsSize = sessions.size();
if (sessionsSize > 0) {
logger.warn("There're " + sessionsSize + " open transient sessions. Print.");
if (logger.isDebugEnabled()) {
for (TransientStoreSession session : sessions) {
TransientSessionImpl impl = session instanceof TransientSessionImpl ? (TransientSessionImpl) session : null;
if (impl != null) {
logger.warn("Not closed session stack trace: ", impl.getStack());
}
}
}
}
}
public boolean entityTypeExists(@NotNull final String entityTypeName) {
try {
return ((PersistentEntityStore) persistentStore).getEntityTypeId(entityTypeName) >= 0;
} catch (Exception e) {
// ignore
}
return false;
}
public void renameEntityTypeRefactoring(@NotNull final String oldEntityTypeName, @NotNull final String newEntityTypeName) {
final TransientSessionImpl s = (TransientSessionImpl) getThreadSession();
if (s == null) {
throw new IllegalStateException("No current thread session.");
}
s.addChangeAndRun(new TransientSessionImpl.MyRunnable() {
@Override
public boolean run() {
((PersistentEntityStore) s.getPersistentTransaction().getStore()).renameEntityType(oldEntityTypeName, newEntityTypeName);
return true;
}
});
}
public void deleteEntityTypeRefactoring(@NotNull final String entityTypeName) {
final TransientSessionImpl s = (TransientSessionImpl) getThreadSession();
if (s == null) {
throw new IllegalStateException("No current thread session.");
}
s.addChangeAndRun(new TransientSessionImpl.MyRunnable() {
@Override
public boolean run() {
((PersistentEntityStoreImpl) s.getPersistentTransaction().getStore()).deleteEntityType(entityTypeName);
return true;
}
});
}
public void deleteEntityRefactoring(@NotNull Entity entity) {
final TransientSessionImpl s = (TransientSessionImpl) getThreadSession();
if (s == null) {
throw new IllegalStateException("No current thread session.");
}
final Entity persistentEntity = (entity instanceof TransientEntity) ? ((TransientEntity) entity).getPersistentEntity() : entity;
if (entity instanceof TransientEntity) {
s.deleteEntity((TransientEntity) entity);
} else {
s.addChangeAndRun(new TransientSessionImpl.MyRunnable() {
public boolean run() {
persistentEntity.delete();
return true;
}
});
}
}
public void deleteLinksRefactoring(@NotNull final Entity entity, @NotNull final String linkName) {
final TransientSessionImpl s = (TransientSessionImpl) getThreadSession();
if (s == null) {
throw new IllegalStateException("No current thread session.");
}
final Entity persistentEntity = (entity instanceof TransientEntity) ? ((TransientEntity) entity).getPersistentEntity() : entity;
s.addChangeAndRun(new TransientSessionImpl.MyRunnable() {
public boolean run() {
persistentEntity.deleteLinks(linkName);
return true;
}
});
}
public void deleteLinkRefactoring(@NotNull final Entity entity, @NotNull final String linkName, @NotNull final Entity link) {
final TransientSessionImpl s = (TransientSessionImpl) getThreadSession();
if (s == null) {
throw new IllegalStateException("No current thread session.");
}
final Entity persistentEntity = (entity instanceof TransientEntity) ? ((TransientEntity) entity).getPersistentEntity() : entity;
final Entity persistentLink = (link instanceof TransientEntity) ? ((TransientEntity) link).getPersistentEntity() : link;
s.addChangeAndRun(new TransientSessionImpl.MyRunnable() {
public boolean run() {
persistentEntity.deleteLink(linkName, persistentLink);
return true;
}
});
}
private TransientStoreSession registerStoreSession(TransientStoreSession s) {
if (!sessions.add(s)) {
throw new IllegalArgumentException("Session is already registered.");
}
currentSession.set(s);
return s;
}
void unregisterStoreSession(TransientStoreSession s) {
if (!sessions.remove(s)) {
throw new IllegalArgumentException("Transient session wasn't previously registered.");
}
currentSession.remove();
}
@Nullable
public TransientStoreSession suspendThreadSession() {
assertOpen();
final TransientStoreSession current = getThreadSession();
if (current != null) {
currentSession.remove();
}
return current;
}
public void addListener(@NotNull TransientStoreSessionListener listener) {
listeners.push(Integer.valueOf(0), listener);
}
@Override
public void addListener(TransientStoreSessionListener listener, final int priority) {
listeners.push(Integer.valueOf(priority), listener);
}
public void removeListener(@NotNull TransientStoreSessionListener listener) {
listeners.remove(listener);
}
void forAllListeners(@NotNull ListenerVisitor v) {
for (final TransientStoreSessionListener listener : listeners) {
v.visit(listener);
}
}
public int sessionsCount() {
return sessions.size();
}
public void dumpSessions(StringBuilder sb) {
for (TransientStoreSession s : sessions) {
sb.append("\n").append(s.toString());
}
}
public boolean isEnumContainerInited(EnumContainer container) {
return initedContainers.contains(container);
}
public void enumContainerInited(EnumContainer container) {
initedContainers.add(container);
}
public void enumContainerLock() throws InterruptedException {
enumContainersLock.acquire();
}
public void enumContainerUnLock() {
enumContainersLock.release();
}
public Entity getCachedEnumValue(@NotNull final String className, @NotNull final String propName) {
return enumCache.get(getEnumKey(className, propName));
}
public void setCachedEnumValue(@NotNull final String className,
@NotNull final String propName, @NotNull final Entity entity) {
enumCache.put(getEnumKey(className, propName), entity);
}
public BasePersistentClassImpl getCachedPersistentClassInstance(@NotNull final String entityType) {
return persistentClassInstanceCache.get(entityType);
}
public BasePersistentClassImpl getCachedPersistentClassInstance(@NotNull final Class extends BasePersistentClassImpl> entityType) {
return persistentClassInstances.get(entityType);
}
public void setCachedPersistentClassInstance(@NotNull final String entityType, @NotNull final BasePersistentClassImpl instance) {
persistentClassInstanceCache.put(entityType, instance);
Class extends BasePersistentClassImpl> clazz = instance.getClass();
if (persistentClassInstances.get(clazz) != null) {
if (logger.isWarnEnabled()) {
logger.warn("Persistent class instance already registered for: " + clazz.getSimpleName());
}
}
persistentClassInstances.put(clazz, instance);
}
private void assertOpen() {
// this flag isn't even volatile, but this is legacy behavior
if (closed) throw new IllegalStateException("Transient store is closed.");
}
public static String getEnumKey(@NotNull final String className, @NotNull final String propName) {
final StringBuilder builder = new StringBuilder(24);
builder.append(propName);
builder.append('@');
builder.append(className);
return builder.toString();
}
interface ListenerVisitor {
void visit(TransientStoreSessionListener listener);
}
}