Something went wrong. Try again.
Backend environment for match hosting for lance.blue
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133package bench;
import java.io.File;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;
import megamek.common.compute.Compute;import megamek.common.game.Game;import megamek.common.game.IGame;import megamek.common.loaders.MekSummaryCache;import megamek.common.scenario.Scenario;import megamek.common.scenario.ScenarioLoader;import megamek.common.units.Entity;import megamek.server.Server;import megamek.server.totalWarfare.TWGameManager;
/** * Does two games in one JVM actually give you two independent games? * * <p>The multi-tenancy question hinges on this. If {@code scenario.createGame()} hands * back Entity instances that are shared with a previously created game - because the * unit cache hands out references rather than copies - then two servers in one JVM are * silently corrupting each other and no amount of memory saving is worth it. * * <p>Checks, in order of how fatal a failure would be: * <ol> * <li>Entity object identity across two games from the same scenario.</li> * <li>Entity ID space overlap (expected to overlap; only a problem if objects are shared too).</li> * <li>Game/Board/Player object identity.</li> * <li>Whether two Servers can bind and coexist at all.</li> * </ol> */public final class IsolationCheck {
public static void main(String[] args) throws Exception { String scenarioPath = args.length > 0 ? args[0] : "data/scenarios/TrainingScenarios/1-FirstRun.mms";
Compute.d6(); MekSummaryCache cache = MekSummaryCache.getInstance(); while (!cache.isInitialized()) { Thread.sleep(250L); } System.out.printf("unit cache ready (%d units)%n%n", cache.getAllMeks().length);
IGame gameA = load(scenarioPath); IGame gameB = load(scenarioPath);
List<Entity> a = new ArrayList<>(((Game) gameA).getEntitiesVector()); List<Entity> b = new ArrayList<>(((Game) gameB).getEntitiesVector()); System.out.printf("game A entities: %d, game B entities: %d%n", a.size(), b.size());
// 1. THE question: are any Entity objects literally shared between games? Set<Integer> identitiesA = new HashSet<>(); for (Entity e : a) { identitiesA.add(System.identityHashCode(e)); } int shared = 0; for (Entity e : b) { if (identitiesA.contains(System.identityHashCode(e))) { shared++; } } System.out.printf("%n[1] shared Entity instances between games: %d -> %s%n", shared, shared == 0 ? "PASS (independent objects)" : "FAIL (games would corrupt each other)");
// 2. ID overlap is fine on its own - each Game indexes its own entities. Set<Integer> idsA = new HashSet<>(); for (Entity e : a) { idsA.add(e.getId()); } int idOverlap = 0; for (Entity e : b) { if (idsA.contains(e.getId())) { idOverlap++; } } System.out.printf("[2] entity ID overlap: %d of %d -> %s%n", idOverlap, b.size(), "expected; per-Game id space, only fatal if [1] failed");
// 3. Container objects must also be distinct. System.out.printf("[3] Game objects distinct: %s%n", gameA != gameB); System.out.printf(" Board objects distinct: %s%n", gameA.getBoard(0) != gameB.getBoard(0)); System.out.printf(" Player lists distinct: %s%n", gameA.getPlayersList() != gameB.getPlayersList());
// 4. Can two Servers coexist in one JVM? System.out.println(); TWGameManager gmA = new TWGameManager(); TWGameManager gmB = new TWGameManager(); Server serverA = new Server("", 9901, gmA); Server serverB = new Server("", 9902, gmB); serverA.setGame(gameA); serverB.setGame(gameB); System.out.printf("[4] two Servers constructed and bound: PASS (ports 9901/9902)%n"); System.out.printf(" server A game == game A: %s%n", serverA.getGame() == gameA); System.out.printf(" server B game == game B: %s%n", serverB.getGame() == gameB); System.out.printf(" servers see different games: %s%n", serverA.getGame() != serverB.getGame());
// 5. The blocker. Server's constructor ends with `serverInstance = this`, and // AbstractGameManager.send() routes every outbound packet through // Server.getServerInstance(). So the moment a second Server exists, the first // game's manager starts transmitting to the second game's connections. // Isolation of the *data* (checks 1-3) is real; isolation of the *transport* // is not. Server current = Server.getServerInstance(); System.out.println(); System.out.printf("[5] Server.getServerInstance() == serverB (newest): %s%n", current == serverB); System.out.printf(" Server.getServerInstance() == serverA (first): %s%n", current == serverA); System.out.printf(" -> game A's manager would send packets to %s%n", current == serverB ? "SERVER B ** WRONG GAME **" : "server A"); System.out.printf(" verdict: %s%n", current == serverA ? "ok" : "FAIL - concurrent games in one JVM corrupt each other's transport");
serverA.die(); serverB.die(); System.exit(0); }
private static IGame load(String scenarioPath) throws Exception { ScenarioLoader loader = new ScenarioLoader(new File(scenarioPath)); Scenario scenario = loader.load(); return scenario.createGame(); }}