/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. All Rights Reserved.
*
* 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.hazelcast.impl;
import com.hazelcast.impl.ConcurrentMapManager.MEvict;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.nio.Data;
import com.hazelcast.nio.Serializer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
public final class ThreadContext {
private final static AtomicInteger newThreadId = new AtomicInteger();
private final Thread thread;
private final Serializer serializer = new Serializer();
private final Map<FactoryImpl, HazelcastInstanceThreadContext> mapHazelcastInstanceContexts = new HashMap<FactoryImpl, HazelcastInstanceThreadContext>(2);
private volatile FactoryImpl currentFactory = null;
private static final ConcurrentMap<Thread, ThreadContext> mapContexts = new ConcurrentHashMap<Thread, ThreadContext>(1000);
private ThreadContext(Thread thread) {
this.thread = thread;
}
public static ThreadContext get() {
Thread currentThread = Thread.currentThread();
ThreadContext threadContext = mapContexts.get(currentThread);
if (threadContext == null) {
threadContext = new ThreadContext(Thread.currentThread());
mapContexts.put(currentThread, threadContext);
Iterator<Thread> threads = mapContexts.keySet().iterator();
while (threads.hasNext()) {
Thread thread = threads.next();
if (!thread.isAlive()) {
threads.remove();
}
}
if (mapContexts.size() > 1000) {
String msg = " ThreadContext is created!! You might have too many threads. Is that normal?";
Logger.getLogger(ThreadContext.class.getName()).log(Level.WARNING, mapContexts.size() + msg);
}
}
return threadContext;
}
public static void shutdownAll() {
mapContexts.clear();
}
public void finalizeTxn() {
getCallContext().finalizeTransaction();
}
public TransactionImpl getTransaction() {
return getCallContext().getTransaction();
}
public long getTxnId() {
return getCallContext().getTxnId();
}
public FactoryImpl getCurrentFactory() {
return currentFactory;
}
public void setCurrentFactory(FactoryImpl currentFactory) {
this.currentFactory = currentFactory;
}
public void reset() {
finalizeTxn();
}
public byte[] toByteArray(Object obj) {
return serializer.toByteArray(obj);
}
public Data toData(Object obj) {
return serializer.writeObject(obj);
}
public Object toObject(Data data) {
return serializer.readObject(data);
}
public HazelcastInstanceThreadContext getHazelcastInstanceThreadContext(FactoryImpl factory) {
if (factory == null) {
ILogger logger = Logger.getLogger(ThreadContext.class.getName());
logger.log(Level.SEVERE, "Factory is null", new Throwable());
}
HazelcastInstanceThreadContext hic = mapHazelcastInstanceContexts.get(factory);
if (hic != null) return hic;
hic = new HazelcastInstanceThreadContext(factory);
mapHazelcastInstanceContexts.put(factory, hic);
return hic;
}
public void shutdown(FactoryImpl factory) {
mapHazelcastInstanceContexts.remove(factory);
}
public CallCache getCallCache(FactoryImpl factory) {
return getHazelcastInstanceThreadContext(factory).getCallCache();
}
/**
* Is this thread remote Java or CSharp Client thread?
*
* @return true if the thread is for Java or CSharp Client, false otherwise
*/
public boolean isClient() {
return getCallContext().isClient();
}
public int createNewThreadId() {
return newThreadId.incrementAndGet();
}
public CallContext getCallContext() {
return getHazelcastInstanceThreadContext(currentFactory).getCallContext();
}
class HazelcastInstanceThreadContext {
FactoryImpl factory;
CallCache callCache;
volatile CallContext callContext = null;
HazelcastInstanceThreadContext(FactoryImpl factory) {
this.factory = factory;
callContext = (new CallContext(createNewThreadId(), false));
}
public CallCache getCallCache() {
if (callCache == null) {
callCache = new CallCache(factory);
}
return callCache;
}
public FactoryImpl getFactory() {
return factory;
}
public CallContext getCallContext() {
return callContext;
}
public void setCallContext(CallContext callContext) {
this.callContext = callContext;
}
}
class CallCache {
final FactoryImpl factory;
final ConcurrentMapManager.MPut mput;
final ConcurrentMapManager.MGet mget;
final ConcurrentMapManager.MRemove mremove;
final ConcurrentMapManager.MEvict mevict;
CallCache(FactoryImpl factory) {
this.factory = factory;
mput = factory.node.concurrentMapManager.new MPut();
mget = factory.node.concurrentMapManager.new MGet();
mremove = factory.node.concurrentMapManager.new MRemove();
mevict = factory.node.concurrentMapManager.new MEvict();
}
public ConcurrentMapManager.MPut getMPut() {
mput.reset();
mput.request.lastTime = System.nanoTime();
return mput;
}
public ConcurrentMapManager.MGet getMGet() {
mget.reset();
mget.request.lastTime = System.nanoTime();
return mget;
}
public ConcurrentMapManager.MRemove getMRemove() {
mremove.reset();
mremove.request.lastTime = System.nanoTime();
return mremove;
}
public MEvict getMEvict() {
mevict.reset();
return mevict;
}
}
public int getThreadId() {
return getCallContext().getThreadId();
}
public void setCallContext(CallContext callContext) {
getHazelcastInstanceThreadContext(currentFactory).setCallContext(callContext);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ThreadContext that = (ThreadContext) o;
if (thread != null ? !thread.equals(that.thread) : that.thread != null) return false;
return true;
}
@Override
public int hashCode() {
return thread != null ? thread.hashCode() : 0;
}
}