/* * Copyright (C) 2012, 2016 higherfrequencytrading.com * Copyright (C) 2016 Roman Leventov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.chronicle.map; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.map.utility.ProcessInstanceLimiter; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; // todo make this example more efficient e.g. not using Serializable. public class ProcessInstanceLimiterMain implements Runnable { private static final long TIME_UPDATE_INTERVAL = 100L; private final String sharedMapName; private final Map<String, Data> theSharedMap; private final Callback callback; private final Map<String, IntWrapper> localUpdates = new ConcurrentHashMap<String, IntWrapper>(); public ProcessInstanceLimiterMain(String sharedMapName, Callback callback) throws IOException { this.sharedMapName = sharedMapName; this.callback = callback; ChronicleMapBuilder<String, Data> builder = ChronicleMapBuilder.of(String.class, Data.class); builder.entries(10000); builder.minSegments(2); File file = new File(System.getProperty("java.io.tmpdir") + "/" + sharedMapName); this.theSharedMap = builder.create(); Thread t = new Thread(this, "ProcessInstanceLimiterMain updater"); t.setDaemon(true); t.start(); } public static void main(String[] args) throws IOException, InterruptedException { Callback callback = new Callback() { public void tooManyProcessesOfType(String processType) { System.out.println("Too many processes of type " + processType + " have been started, so exiting this process"); System.exit(0); } public void noDefinitionForProcessesOfType(String processType) { System.out.println("No definition for processes of type " + processType + " has been set, so exiting this process"); System.exit(0); } }; ProcessInstanceLimiterMain limiter = new ProcessInstanceLimiterMain("test", callback); limiter.setMaxNumberOfProcessesOfType("x", 2); limiter.startingProcessOfType("x"); Jvm.pause(60L * 1000L); } public static void pause(long pause) { ProcessInstanceLimiter.pause(pause); } public void run() { //every TIME_UPDATE_INTERVAL milliseconds, update the time while (true) { try { pause(TIME_UPDATE_INTERVAL); String processType; for (Entry<String, IntWrapper> entry : this.localUpdates.entrySet()) { processType = entry.getKey(); int index = entry.getValue().intValue; Data data = this.theSharedMap.get(processType); if (data != null) { long timenow = System.currentTimeMillis(); data.time[index] = timenow; this.theSharedMap.put(processType, data); while ((data = this.theSharedMap.get(processType)).time[index] != timenow) { data.time[index] = timenow; this.theSharedMap.put(processType, data); } } } } catch (Exception e) { // TODO e.printStackTrace(); } } } public void startingProcessOfType(String processType) { Data data = this.theSharedMap.get(processType); if (data == null) { this.callback.noDefinitionForProcessesOfType(processType); this.callback.tooManyProcessesOfType(processType); return; } long[] times1 = data.time; pause(2L * TIME_UPDATE_INTERVAL); long[] times2 = this.theSharedMap.get(processType).time; for (int i = 0; i < times1.length; i++) { if (times2[i] == times1[i]) { //we have an index which has not been updated in 200ms //so we have a spare slot - use this slot this.localUpdates.put(processType, new IntWrapper(i)); return; } } this.callback.tooManyProcessesOfType(processType); } public void setMaxNumberOfProcessesOfType(String processType, int maxNumberOfProcessesAllowed) { this.theSharedMap.put(processType, new Data(processType, maxNumberOfProcessesAllowed)); } public interface Callback { public void tooManyProcessesOfType(String processType); public void noDefinitionForProcessesOfType(String processType); } public static class Data implements Serializable { /** * generated serialVersionUID */ private static final long serialVersionUID = 9163018396438735118L; String processType; int maxNumberOfProcessesAllowed; long[] time; public Data(String processType, int maxNumberOfProcessesAllowed) { this.processType = processType; this.maxNumberOfProcessesAllowed = maxNumberOfProcessesAllowed; this.time = new long[maxNumberOfProcessesAllowed]; } } public static class IntWrapper { int intValue; public IntWrapper(int intValue) { this.intValue = intValue; } } }