final Set<UUID> getPlayers() { ImmutableSet.Builder<UUID> setBuilder = ImmutableSet.builder(); if (pool != null) { try (Jedis rsc = pool.getResource()) { List<String> keys = new ArrayList<>(); for (String i : getServerIds()) { keys.add("proxy:" + i + ":usersOnline"); } if (!keys.isEmpty()) { Set<String> users = rsc.sunion(keys.toArray(new String[keys.size()])); if (users != null && !users.isEmpty()) { for (String user : users) { try { setBuilder = setBuilder.add(UUID.fromString(user)); } catch (IllegalArgumentException ignored) { } } } } } catch (JedisConnectionException e) { // Redis server has disappeared! getLogger() .log( Level.SEVERE, "Unable to get connection from pool - did your Redis server go away?", e); throw new RuntimeException("Unable to get all players online", e); } } return setBuilder.build(); }
@Test(expected = JedisAskDataException.class) public void testThrowAskException() { int keySlot = JedisClusterCRC16.getSlot("test"); String node3Id = JedisClusterTestUtil.getNodeId(node3.clusterNodes()); node2.clusterSetSlotMigrating(keySlot, node3Id); node2.get("test"); }
private List<String> getCurrentServerIds(boolean nag, boolean lagged) { try (Jedis jedis = pool.getResource()) { long time = getRedisTime(jedis.time()); int nagTime = 0; if (nag) { nagTime = nagAboutServers.decrementAndGet(); if (nagTime <= 0) { nagAboutServers.set(10); } } ImmutableList.Builder<String> servers = ImmutableList.builder(); Map<String, String> heartbeats = jedis.hgetAll("heartbeats"); for (Map.Entry<String, String> entry : heartbeats.entrySet()) { try { long stamp = Long.parseLong(entry.getValue()); if (lagged ? time >= stamp + 30 : time <= stamp + 30) servers.add(entry.getKey()); else if (nag && nagTime <= 0) { getLogger() .severe( entry.getKey() + " is " + (time - stamp) + " seconds behind! (Time not synchronized or server down?)"); } } catch (NumberFormatException ignored) { } } return servers.build(); } catch (JedisConnectionException e) { getLogger().log(Level.SEVERE, "Unable to fetch server IDs", e); return Collections.singletonList(configuration.getServerId()); } }
@Test public void testClusterKeySlot() { // It assumes JedisClusterCRC16 is correctly implemented assertEquals( node1.clusterKeySlot("foo{bar}zap}").intValue(), JedisClusterCRC16.getSlot("foo{bar}zap")); assertEquals( node1.clusterKeySlot("{user1000}.following").intValue(), JedisClusterCRC16.getSlot("{user1000}.following")); }
@Test(expected = JedisClusterMaxRedirectionsException.class) public void testRedisClusterMaxRedirections() { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379)); JedisCluster jc = new JedisCluster(jedisClusterNode); int slot51 = JedisClusterCRC16.getSlot("51"); // This will cause an infinite redirection loop node2.clusterSetSlotMigrating(slot51, JedisClusterTestUtil.getNodeId(node3.clusterNodes())); jc.set("51", "foo"); }
@Test public void testAskResponse() throws InterruptedException { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379)); JedisCluster jc = new JedisCluster(jedisClusterNode); int slot51 = JedisClusterCRC16.getSlot("51"); node3.clusterSetSlotImporting(slot51, JedisClusterTestUtil.getNodeId(node2.clusterNodes())); node2.clusterSetSlotMigrating(slot51, JedisClusterTestUtil.getNodeId(node3.clusterNodes())); jc.set("51", "foo"); assertEquals("foo", jc.get("51")); }
public Set<UUID> getPlayersOnProxy(String server) { checkArgument(getServerIds().contains(server), server + " is not a valid proxy ID"); try (Jedis jedis = pool.getResource()) { Set<String> users = jedis.smembers("proxy:" + server + ":usersOnline"); ImmutableSet.Builder<UUID> builder = ImmutableSet.builder(); for (String user : users) { builder.add(UUID.fromString(user)); } return builder.build(); } }
public void onStart(Application app) { JedisPool p = app.plugin(RedisPlugin.class).jedisPool(); // uncomment to test sentinel setup // JedisSentinelPool p = app.plugin(RedisPlugin.class).jedisSentinelPool(); Jedis j = p.getResource(); j.set("foo", "yay"); p.returnResource(j); Cache.set("foo2", 5); Map<String, String> m = new HashMap<String, String>(); m.put("test", "value"); Cache.set("foo3", m); }
@Test(expected = JedisClusterMaxRedirectionsException.class, timeout = 2000) public void testReturnConnectionOnRedirection() { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379)); JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(1); JedisCluster jc = new JedisCluster(jedisClusterNode, 0, 2, config); // This will cause an infinite redirection between node 2 and 3 node3.clusterSetSlotMigrating(15363, JedisClusterTestUtil.getNodeId(node2.clusterNodes())); jc.get("e"); }
final void sendChannelMessage(String channel, String message) { try (Jedis jedis = pool.getResource()) { jedis.publish(channel, message); } catch (JedisConnectionException e) { // Redis server has disappeared! getLogger() .log( Level.SEVERE, "Unable to get connection from pool - did your Redis server go away?", e); throw new RuntimeException("Unable to publish channel message", e); } }
@Test public void testRecalculateSlotsWhenMoved() throws InterruptedException { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379)); JedisCluster jc = new JedisCluster(jedisClusterNode); int slot51 = JedisClusterCRC16.getSlot("51"); node2.clusterDelSlots(slot51); node3.clusterDelSlots(slot51); node3.clusterAddSlots(slot51); JedisClusterTestUtil.waitForClusterReady(node1, node2, node3); jc.set("51", "foo"); assertEquals("foo", jc.get("51")); }
@Test public void testJedisClusterTimeout() { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort(nodeInfo1.getHost(), nodeInfo1.getPort())); JedisCluster jc = new JedisCluster(jedisClusterNode, 4000); for (JedisPool pool : jc.getClusterNodes().values()) { Jedis jedis = pool.getResource(); assertEquals(jedis.getClient().getConnectionTimeout(), 4000); assertEquals(jedis.getClient().getSoTimeout(), 4000); jedis.close(); } }
@Test(timeout = 2000) public void testReturnConnectionOnJedisConnectionException() throws InterruptedException { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379)); JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(1); JedisCluster jc = new JedisCluster(jedisClusterNode, config); Jedis j = jc.getClusterNodes().get("127.0.0.1:7380").getResource(); ClientKillerUtil.tagClient(j, "DEAD"); ClientKillerUtil.killClient(j, "DEAD"); j.close(); jc.get("test"); }
@Test public void testCalculateConnectionPerSlot() { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379)); JedisCluster jc = new JedisCluster(jedisClusterNode); jc.set("foo", "bar"); jc.set("test", "test"); assertEquals("bar", node3.get("foo")); assertEquals("test", node2.get("test")); JedisCluster jc2 = new JedisCluster(new HostAndPort("127.0.0.1", 7379)); jc2.set("foo", "bar"); jc2.set("test", "test"); assertEquals("bar", node3.get("foo")); assertEquals("test", node2.get("test")); }
private boolean isAnyNodeHandshaking(Jedis node) { String infoOutput = node.clusterNodes(); for (String infoLine : infoOutput.split("\n")) { if (infoLine.contains("handshake")) { return true; } } return false; }
@AfterClass public static void cleanUp() { node1.flushDB(); node2.flushDB(); node3.flushDB(); node4.flushDB(); node1.clusterReset(Reset.SOFT); node2.clusterReset(Reset.SOFT); node3.clusterReset(Reset.SOFT); node4.clusterReset(Reset.SOFT); }
@Test public void testMovedExceptionParameters() { try { node1.set("foo", "bar"); } catch (JedisMovedDataException jme) { assertEquals(12182, jme.getSlot()); assertEquals(new HostAndPort("127.0.0.1", 7381), jme.getTargetNode()); return; } fail(); }
@Test public void testClusterFlushSlots() { String slotRange = getNodeServingSlotRange(node1.clusterNodes()); assertNotNull(slotRange); try { node1.clusterFlushSlots(); assertNull(getNodeServingSlotRange(node1.clusterNodes())); } finally { // rollback String[] rangeInfo = slotRange.split("-"); int lower = Integer.parseInt(rangeInfo[0]); int upper = Integer.parseInt(rangeInfo[1]); int[] node1Slots = new int[upper - lower + 1]; for (int i = 0; lower <= upper; ) { node1Slots[i++] = lower++; } node1.clusterAddSlots(node1Slots); } }
@Test public void testClusterCountKeysInSlot() { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort(nodeInfo1.getHost(), nodeInfo1.getPort())); JedisCluster jc = new JedisCluster(jedisClusterNode); for (int index = 0; index < 5; index++) { jc.set("foo{bar}" + index, "hello"); } int slot = JedisClusterCRC16.getSlot("foo{bar}"); assertEquals(5, node1.clusterCountKeysInSlot(slot).intValue()); }
@Override public void onDisable() { if (pool != null) { // Poison the PubSub listener psl.poison(); getProxy().getScheduler().cancel(this); integrityCheck.cancel(); heartbeatTask.cancel(); getProxy().getPluginManager().unregisterListeners(this); try (Jedis tmpRsc = pool.getResource()) { tmpRsc.hdel("heartbeats", configuration.getServerId()); if (tmpRsc.scard("proxy:" + configuration.getServerId() + ":usersOnline") > 0) { Set<String> players = tmpRsc.smembers("proxy:" + configuration.getServerId() + ":usersOnline"); for (String member : players) RedisUtil.cleanUpPlayer(member, tmpRsc); } } pool.destroy(); } }
@Override public void run() { boolean broken = false; try (Jedis rsc = pool.getResource()) { try { jpsh = new JedisPubSubHandler(); rsc.subscribe( jpsh, "redisbungee-" + configuration.getServerId(), "redisbungee-allservers", "redisbungee-data"); } catch (Exception e) { // FIXME: Extremely ugly hack // Attempt to unsubscribe this instance and try again. getLogger().log(Level.INFO, "PubSub error, attempting to recover.", e); jpsh.unsubscribe(); broken = true; } } if (broken) { run(); } }
@Test public void testReadonly() throws Exception { node1.clusterMeet(localHost, nodeInfoSlave2.getPort()); JedisClusterTestUtil.waitForClusterReady(node1, node2, node3, nodeSlave2); for (String nodeInfo : node2.clusterNodes().split("\n")) { if (nodeInfo.contains("myself")) { nodeSlave2.clusterReplicate(nodeInfo.split(" ")[0]); break; } } try { nodeSlave2.get("test"); fail(); } catch (JedisMovedDataException e) { } nodeSlave2.readonly(); nodeSlave2.get("test"); nodeSlave2.clusterReset(Reset.SOFT); nodeSlave2.flushDB(); }
@Before public void setUp() throws Exception { Jedis jedis = new Jedis(redis1.host, redis1.port); jedis.auth("foobared"); jedis.flushAll(); jedis.disconnect(); jedis = new Jedis(redis2.host, redis2.port); jedis.auth("foobared"); jedis.flushAll(); jedis.disconnect(); List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(); JedisShardInfo si1 = new JedisShardInfo(redis1.host, redis1.port); si1.setPassword("foobared"); shards.add(si1); JedisShardInfo si2 = new JedisShardInfo(redis2.host, redis2.port); si2.setPassword("foobared"); shards.add(si2); this.jedis = new ShardedJedis(shards); }
@Test public void testStableSlotWhenMigratingNodeOrImportingNodeIsNotSpecified() throws InterruptedException { Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort(nodeInfo1.getHost(), nodeInfo1.getPort())); JedisCluster jc = new JedisCluster(jedisClusterNode); int slot51 = JedisClusterCRC16.getSlot("51"); jc.set("51", "foo"); // node2 is responsible of taking care of slot51 (7186) node3.clusterSetSlotImporting(slot51, JedisClusterTestUtil.getNodeId(node2.clusterNodes())); assertEquals("foo", jc.get("51")); node3.clusterSetSlotStable(slot51); assertEquals("foo", jc.get("51")); node2.clusterSetSlotMigrating(slot51, JedisClusterTestUtil.getNodeId(node3.clusterNodes())); // assertEquals("foo", jc.get("51")); // it leads Max Redirections node2.clusterSetSlotStable(slot51); assertEquals("foo", jc.get("51")); }
@Test(expected = JedisMovedDataException.class) public void testThrowMovedException() { node1.set("foo", "bar"); }
/** slot->nodes 15363 node3 e */ @Test public void testMigrate() { log.info("test migrate slot"); Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(nodeInfo1); JedisCluster jc = new JedisCluster(jedisClusterNode); String node3Id = JedisClusterTestUtil.getNodeId(node3.clusterNodes()); String node2Id = JedisClusterTestUtil.getNodeId(node2.clusterNodes()); node3.clusterSetSlotMigrating(15363, node2Id); node2.clusterSetSlotImporting(15363, node3Id); try { node2.set("e", "e"); } catch (JedisMovedDataException jme) { assertEquals(15363, jme.getSlot()); assertEquals(new HostAndPort(localHost, nodeInfo3.getPort()), jme.getTargetNode()); } try { node3.set("e", "e"); } catch (JedisAskDataException jae) { assertEquals(15363, jae.getSlot()); assertEquals(new HostAndPort(localHost, nodeInfo2.getPort()), jae.getTargetNode()); } jc.set("e", "e"); try { node2.get("e"); } catch (JedisMovedDataException jme) { assertEquals(15363, jme.getSlot()); assertEquals(new HostAndPort(localHost, nodeInfo3.getPort()), jme.getTargetNode()); } try { node3.get("e"); } catch (JedisAskDataException jae) { assertEquals(15363, jae.getSlot()); assertEquals(new HostAndPort(localHost, nodeInfo2.getPort()), jae.getTargetNode()); } assertEquals("e", jc.get("e")); node2.clusterSetSlotNode(15363, node2Id); node3.clusterSetSlotNode(15363, node2Id); // assertEquals("e", jc.get("e")); assertEquals("e", node2.get("e")); // assertEquals("e", node3.get("e")); }
@Test public void testMigrateToNewNode() throws InterruptedException { log.info("test migrate slot to new node"); Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(nodeInfo1); JedisCluster jc = new JedisCluster(jedisClusterNode); node4.clusterMeet(localHost, nodeInfo1.getPort()); String node3Id = JedisClusterTestUtil.getNodeId(node3.clusterNodes()); String node4Id = JedisClusterTestUtil.getNodeId(node4.clusterNodes()); JedisClusterTestUtil.waitForClusterReady(node4); node3.clusterSetSlotMigrating(15363, node4Id); node4.clusterSetSlotImporting(15363, node3Id); try { node4.set("e", "e"); } catch (JedisMovedDataException jme) { assertEquals(15363, jme.getSlot()); assertEquals(new HostAndPort(localHost, nodeInfo3.getPort()), jme.getTargetNode()); } try { node3.set("e", "e"); } catch (JedisAskDataException jae) { assertEquals(15363, jae.getSlot()); assertEquals(new HostAndPort(localHost, nodeInfo4.getPort()), jae.getTargetNode()); } jc.set("e", "e"); try { node4.get("e"); } catch (JedisMovedDataException jme) { assertEquals(15363, jme.getSlot()); assertEquals(new HostAndPort(localHost, nodeInfo3.getPort()), jme.getTargetNode()); } try { node3.get("e"); } catch (JedisAskDataException jae) { assertEquals(15363, jae.getSlot()); assertEquals(new HostAndPort(localHost, nodeInfo4.getPort()), jae.getTargetNode()); } assertEquals("e", jc.get("e")); node4.clusterSetSlotNode(15363, node4Id); node3.clusterSetSlotNode(15363, node4Id); // assertEquals("e", jc.get("e")); assertEquals("e", node4.get("e")); // assertEquals("e", node3.get("e")); }
private void loadConfig() throws IOException, JedisConnectionException { if (!getDataFolder().exists()) { getDataFolder().mkdir(); } File file = new File(getDataFolder(), "config.yml"); if (!file.exists()) { file.createNewFile(); try (InputStream in = getResourceAsStream("example_config.yml"); OutputStream out = new FileOutputStream(file)) { ByteStreams.copy(in, out); } } final Configuration configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(file); final String redisServer = configuration.getString("redis-server", "localhost"); final int redisPort = configuration.getInt("redis-port", 6379); String redisPassword = configuration.getString("redis-password"); String serverId = configuration.getString("server-id"); if (redisPassword != null && (redisPassword.isEmpty() || redisPassword.equals("none"))) { redisPassword = null; } // Configuration sanity checks. if (serverId == null || serverId.isEmpty()) { throw new RuntimeException("server-id is not specified in the configuration or is empty"); } if (redisServer != null && !redisServer.isEmpty()) { final String finalRedisPassword = redisPassword; FutureTask<JedisPool> task = new FutureTask<>( new Callable<JedisPool>() { @Override public JedisPool call() throws Exception { // With recent versions of Jedis, we must set the classloader to the one // BungeeCord used // to load RedisBungee with. ClassLoader previous = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(RedisBungee.class.getClassLoader()); // Create the pool... JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(configuration.getInt("max-redis-connections", 8)); JedisPool pool = new JedisPool(config, redisServer, redisPort, 0, finalRedisPassword); // Reset classloader and return the pool Thread.currentThread().setContextClassLoader(previous); return pool; } }); getProxy().getScheduler().runAsync(this, task); try { pool = task.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException("Unable to create Redis pool", e); } // Test the connection try (Jedis rsc = pool.getResource()) { rsc.ping(); // If that worked, now we can check for an existing, alive Bungee: File crashFile = new File(getDataFolder(), "restarted_from_crash.txt"); if (crashFile.exists()) { crashFile.delete(); } else if (rsc.hexists("heartbeats", serverId)) { try { long value = Long.parseLong(rsc.hget("heartbeats", serverId)); if (System.currentTimeMillis() < value + 20000) { getLogger() .severe( "You have launched a possible impostor BungeeCord instance. Another instance is already running."); getLogger() .severe("For data consistency reasons, RedisBungee will now disable itself."); getLogger() .severe( "If this instance is coming up from a crash, create a file in your RedisBungee plugins directory with the name 'restarted_from_crash.txt' and RedisBungee will not perform this check."); throw new RuntimeException("Possible impostor instance!"); } } catch (NumberFormatException ignored) { } } FutureTask<Void> task2 = new FutureTask<>( new Callable<Void>() { @Override public Void call() throws Exception { httpClient = new OkHttpClient(); Dispatcher dispatcher = new Dispatcher(getExecutorService()); httpClient.setDispatcher(dispatcher); NameFetcher.setHttpClient(httpClient); UUIDFetcher.setHttpClient(httpClient); RedisBungee.configuration = new RedisBungeeConfiguration(RedisBungee.this.getPool(), configuration); return null; } }); getProxy().getScheduler().runAsync(this, task2); try { task2.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException("Unable to create HTTP client", e); } getLogger().log(Level.INFO, "Successfully connected to Redis."); } catch (JedisConnectionException e) { pool.destroy(); pool = null; throw e; } } else { throw new RuntimeException("No redis server specified!"); } }
@Test public void testClusterForgetNode() throws InterruptedException { // at first, join node4 to cluster node1.clusterMeet("127.0.0.1", nodeInfo4.getPort()); String node7Id = JedisClusterTestUtil.getNodeId(node4.clusterNodes()); JedisClusterTestUtil.assertNodeIsKnown(node3, node7Id, 1000); JedisClusterTestUtil.assertNodeIsKnown(node2, node7Id, 1000); JedisClusterTestUtil.assertNodeIsKnown(node1, node7Id, 1000); assertNodeHandshakeEnded(node3, 1000); assertNodeHandshakeEnded(node2, 1000); assertNodeHandshakeEnded(node1, 1000); assertEquals(4, node1.clusterNodes().split("\n").length); assertEquals(4, node2.clusterNodes().split("\n").length); assertEquals(4, node3.clusterNodes().split("\n").length); // do cluster forget node1.clusterForget(node7Id); node2.clusterForget(node7Id); node3.clusterForget(node7Id); JedisClusterTestUtil.assertNodeIsUnknown(node1, node7Id, 1000); JedisClusterTestUtil.assertNodeIsUnknown(node2, node7Id, 1000); JedisClusterTestUtil.assertNodeIsUnknown(node3, node7Id, 1000); assertEquals(3, node1.clusterNodes().split("\n").length); assertEquals(3, node2.clusterNodes().split("\n").length); assertEquals(3, node3.clusterNodes().split("\n").length); }
@Before public void setUp() throws InterruptedException { node1 = new Jedis(nodeInfo1.getHost(), nodeInfo1.getPort()); node1.connect(); node1.flushAll(); node2 = new Jedis(nodeInfo2.getHost(), nodeInfo2.getPort()); node2.connect(); node2.flushAll(); node3 = new Jedis(nodeInfo3.getHost(), nodeInfo3.getPort()); node3.connect(); node3.flushAll(); node4 = new Jedis(nodeInfo4.getHost(), nodeInfo4.getPort()); node4.connect(); node4.flushAll(); nodeSlave2 = new Jedis(nodeInfoSlave2.getHost(), nodeInfoSlave2.getPort()); nodeSlave2.connect(); nodeSlave2.flushAll(); // ---- configure cluster // add nodes to cluster node1.clusterMeet(localHost, nodeInfo2.getPort()); node1.clusterMeet(localHost, nodeInfo3.getPort()); // split available slots across the three nodes int slotsPerNode = JedisCluster.HASHSLOTS / 3; int[] node1Slots = new int[slotsPerNode]; int[] node2Slots = new int[slotsPerNode + 1]; int[] node3Slots = new int[slotsPerNode]; for (int i = 0, slot1 = 0, slot2 = 0, slot3 = 0; i < JedisCluster.HASHSLOTS; i++) { if (i < slotsPerNode) { node1Slots[slot1++] = i; } else if (i > slotsPerNode * 2) { node3Slots[slot3++] = i; } else { node2Slots[slot2++] = i; } } node1.clusterAddSlots(node1Slots); node2.clusterAddSlots(node2Slots); node3.clusterAddSlots(node3Slots); JedisClusterTestUtil.waitForClusterReady(node1, node2, node3); }