package com.tesora.dve.clock;
/*
* #%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 com.tesora.dve.exceptions.PEException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.*;
import java.util.concurrent.atomic.AtomicReference;
public class SwitchingTimingService implements TimingService, TimingServiceConfiguration {
static final Logger logger = LoggerFactory.getLogger(SwitchingTimingService.class);
static TimingService NOOP = new NoopTimingService();
AtomicReference<TimingService> delegate = new AtomicReference<>(NOOP);
Path baseLogDir;
public SwitchingTimingService(Path baseLogDir) {
if (baseLogDir == null){
try {
this.baseLogDir = Files.createTempDirectory("tesora_perf");
logger.warn("Base logging directory was not set, putting perf trace logs in temp dir, "+this.baseLogDir);
} catch (IOException e) {
logger.warn("Base logging directory was not set and a temp directory could not be created, perf trace logging cannot be enabled.");
this.baseLogDir = null;
}
} else {
this.baseLogDir = baseLogDir;
}
}
@Override
public void setTimingEnabled(boolean enabled) throws PEException {
if (enabled)
enableTiming();
else
disableTiming();
}
private void disableTiming() {
changeServiceAtomically(NOOP);
}
private void enableTiming() throws PEException {
if (logger.isDebugEnabled())
logger.debug("Trying to enable perf trace, base dir is "+baseLogDir);
if (baseLogDir == null)
return; //no target directory, ignore.
Path perfLogFile = null;
try {
StampClock clock = new StampClock();
perfLogFile = baseLogDir.resolve("perfTrace.log");
DefaultTimingService nextService = new DefaultTimingService(clock,perfLogFile);
changeServiceAtomically(nextService);
} catch (Exception e){
String message = "Could not create performance log file, " + perfLogFile;
logger.warn(message);
throw new PEException(message,e);
}
}
private void changeServiceAtomically(TimingService nextService) {
for(;;){
TimingService previous = delegate.get();
if (delegate.compareAndSet(previous,nextService)){
//we could notify the new timing service it is installed, but it may already be receiving requests.
closeServiceIfNeeded(previous);
break;
}
}
}
private void closeServiceIfNeeded(TimingService current) {
if (current instanceof Closeable){
Closeable closeMe = (Closeable)current;
try{
closeMe.close();
} catch (Exception e){
logger.warn("Problem closing existing timing service, {} ,exception was ",e);
}
}
}
@Override
public Timer getTimerOnThread() {
return delegate.get().getTimerOnThread();
}
@Override
public void detachTimerOnThread() {
delegate.get().detachTimerOnThread();
}
@Override
public Timer attachTimerOnThread(Timer parent) {
return delegate.get().attachTimerOnThread(parent);
}
@Override
public Timer startSubTimer(Enum location) {
return delegate.get().startSubTimer(location);
}
}