package com.tesora.dve.variables; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.concurrent.ConcurrentHashMap; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.groupmanager.GroupManager; import com.tesora.dve.membership.GroupTopicPublisher; import com.tesora.dve.groupmanager.OnGlobalConfigChangeMessage; import com.tesora.dve.locking.ClusterLock; import com.tesora.dve.lockmanager.LockClient; import com.tesora.dve.singleton.Singletons; /* * The global variable store holds both global values as well as session values that have no * global equivalent. The global values come from the group services; the session values come * from the catalog. */ public class ServerGlobalVariableStore extends AbstractVariableStore implements GlobalVariableStore, LockClient { public static final ServerGlobalVariableStore INSTANCE = new ServerGlobalVariableStore(); private static final String GLOBAL_VAR_STORE_LOCK_NAME = "DVE.Global.Variables"; // this is a cache that's built from the group services copy // we populate it lazily private final ConcurrentHashMap<VariableHandler<?>,ValueReference<?>> cache = new ConcurrentHashMap<VariableHandler<?>,ValueReference<?>>(); // make it public for the trans exec engine private ServerGlobalVariableStore() { super(); } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public <Type> ValueReference<Type> getReference(VariableHandler<Type> vh) { ValueReference vr = cache.get(vh); if (vr == null) vr = readValue(vh); return vr; } @SuppressWarnings({ "unchecked", "rawtypes" }) private <Type> ValueReference<Type> readValue(VariableHandler<Type> vh) { ClusterLock lock = getLock(); try { lock.sharedLock(this,"repopulate global var cache for read"); String value = GroupManager.getCoordinationServices().getGlobalVariable(vh.getName()); if (value == null) return null; ValueReference<Type> out = new ValueReference(vh,vh.toInternal(value)); cache.put(vh,out); return out; } catch (PEException pe) { throw new VariableException(pe); } finally { lock.sharedUnlock(this, "repopulate global var cache for read"); } } @Override public <Type> void setValue(VariableHandler<Type> vh, Type t) { setValueInternal(vh,t,false); } @Override public <Type> void addVariable(VariableHandler<Type> vh, Type t) { setValueInternal(vh,t,true); } @SuppressWarnings("unchecked") private <Type> void setValueInternal(VariableHandler<Type> vh, Type t, boolean added) { // in the write scenario, we lock first, then write through to the group manager map String newValue = vh.toMap(t); ClusterLock lock = getLock(); try { lock.exclusiveLock(this, "set global var"); // call into the group manager for this bit GroupManager.getCoordinationServices().setGlobalVariable(vh.getName(), newValue); // then send a message invalidating Singletons.require(GroupTopicPublisher.class).publish(new OnGlobalConfigChangeMessage(vh.getName(), newValue,added)); } finally { lock.exclusiveUnlock(this, "set global var"); } } private ClusterLock getLock() { return GroupManager.getCoordinationServices().getClusterLock(GLOBAL_VAR_STORE_LOCK_NAME); } @Override public String getName() { return "GlobalVariableManager"; } @SuppressWarnings("rawtypes") @Override public void invalidate(VariableHandler vh) { cache.remove(vh); } @SuppressWarnings({ "unchecked", "rawtypes" }) public LocalVariableStore buildNewLocalStore() { VariableManager vm = Singletons.require(VariableService.class).getVariableManager(); LocalVariableStore out = new LocalVariableStore(); for(VariableHandler vh : vm.getAllHandlers()) { out.setInternal(vh, getReference(vh).get()); } return out; } @Override public boolean isServer() { return true; } public void reset() { cache.clear(); } }