From 2e8508a32c8b368bc930d9be427508452abdad0c Mon Sep 17 00:00:00 2001 From: RoyceDa Date: Fri, 20 Mar 2026 19:41:02 +0200 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8?= =?UTF-8?q?=20ConcurrentModificationException=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D0=BC=D0=BD=D0=BE=D0=B6=D0=B5=D1=81=D1=82=D0=B2=D0=B5=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/build.yaml | 1 + .../java/im/rosetta/client/ClientManager.java | 10 +++--- .../io/orprotocol/index/ClientIndexer.java | 34 ++++++++----------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 837a2e3..2cd3697 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -1,4 +1,5 @@ name: Build rosetta-wss +run-name: Build and Deploy WSS on: push: branches: diff --git a/src/main/java/im/rosetta/client/ClientManager.java b/src/main/java/im/rosetta/client/ClientManager.java index 0ec7650..2bc28fd 100644 --- a/src/main/java/im/rosetta/client/ClientManager.java +++ b/src/main/java/im/rosetta/client/ClientManager.java @@ -1,7 +1,7 @@ package im.rosetta.client; -import java.util.HashSet; import java.util.List; +import java.util.Set; import im.rosetta.client.tags.ECIAuthentificate; @@ -33,7 +33,7 @@ public class ClientManager { } public boolean isClientConnected(String publicKey) { - HashSet clients = this.clientIndexer.getClients(ECIAuthentificate.class, "publicKey", publicKey); + Set clients = this.clientIndexer.getClients(ECIAuthentificate.class, "publicKey", publicKey); if(clients == null){ /** * Нет клиентов с таким публичным ключом @@ -59,7 +59,7 @@ public class ClientManager { * @throws ProtocolException если произошла ошибка при отправке пакета клиенту */ public void sendPacketToAuthorizedPK(String publicKey, Packet packet) throws ProtocolException { - HashSet clients = this.clientIndexer.getClients(ECIAuthentificate.class, "publicKey", publicKey); + Set clients = this.clientIndexer.getClients(ECIAuthentificate.class, "publicKey", publicKey); if(clients == null){ /** * Нет клиентов с таким публичным ключом, значит отправлять некому @@ -91,7 +91,7 @@ public class ClientManager { */ public void retranslate(Client client, Packet packet) throws ProtocolException{ ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class); - HashSet clients = this.clientIndexer + Set clients = this.clientIndexer .getClients(ECIAuthentificate.class, "publicKey", eciAuthentificate.getPublicKey()); if(clients == null){ /** @@ -129,7 +129,7 @@ public class ClientManager { * @return список клиентов с таким публичным ключом, может быть пустым, если клиентов с таким публичным ключом нет */ public List getPKClients(String publicKey) { - HashSet clients = this.clientIndexer.getClients(ECIAuthentificate.class, "publicKey", publicKey); + Set clients = this.clientIndexer.getClients(ECIAuthentificate.class, "publicKey", publicKey); if(clients == null){ /** * Нет клиентов с таким публичным ключом diff --git a/src/main/java/io/orprotocol/index/ClientIndexer.java b/src/main/java/io/orprotocol/index/ClientIndexer.java index 2c29859..ff83804 100644 --- a/src/main/java/io/orprotocol/index/ClientIndexer.java +++ b/src/main/java/io/orprotocol/index/ClientIndexer.java @@ -1,7 +1,7 @@ package io.orprotocol.index; -import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import io.orprotocol.client.Client; @@ -19,14 +19,8 @@ public class ClientIndexer { * Ключ третьего уровня - значение поля. * Значение - клиент. * Структура: tagClass -> indexName -> indexValue -> Client - * - * - * В качестве клиента используем HashSet потому что он очень хорош для операции contains, - * в отличие от ArrayList, который при поиске перебирает элементы один за другим, - * HashSet использует хэш таблицу и находит нужный объект почти - * мгновенно, независимо от того, 10 там элементов или миллион. */ - private final Map, Map>>> indices + private final ConcurrentHashMap, ConcurrentHashMap>>> indices = new ConcurrentHashMap<>(); public void indexTag(Client client, Class tagClass, T tag) { @@ -53,7 +47,7 @@ public class ClientIndexer { * Если использовать putIfAbsent, то он вернет null если значение там уже есть, * что не подходит */ - Map>> tagIndices = this.indices.computeIfAbsent( + ConcurrentHashMap>> tagIndices = this.indices.computeIfAbsent( tagClass, k -> new ConcurrentHashMap<>()); @@ -76,7 +70,7 @@ public class ClientIndexer { /** * Инициализируем имя индекса, почему compute, а не put - написано выше */ - Map> index = tagIndices.computeIfAbsent( + Map> index = tagIndices.computeIfAbsent( indexName, k -> new ConcurrentHashMap<>() ); @@ -86,7 +80,7 @@ public class ClientIndexer { * с одинковыми индексами, хотя такого лучше избегать, желательно чтобы индексы * были уникальными, тогда обработка будет быстрее всего */ - HashSet clients = index.computeIfAbsent(indexValue, k -> new HashSet<>()); + Set clients = index.computeIfAbsent(indexValue, k -> ConcurrentHashMap.newKeySet()); /** * Добавляем клиента в инициализиованный индекс */ @@ -117,7 +111,7 @@ public class ClientIndexer { * @internal */ public void removeTagIndex(Client client, Class tagClass) { - Map>> tagIndices = indices.get(tagClass); + ConcurrentHashMap>> tagIndices = indices.get(tagClass); if (tagIndices == null) { /** * Индекса и так не было, удалять нечего @@ -128,12 +122,12 @@ public class ClientIndexer { /** * Удаляем все ключи indexName по tagClass если Client == client */ - for (Map> index : tagIndices.values()) { + for (ConcurrentHashMap> index : tagIndices.values()) { /** * contains всегда использует переопределенный equals, по этому * обьекты клиентов сравниваются нормально */ - for(HashSet clients : index.values()){ + for(Set clients : index.values()){ if(!clients.contains(client)){ continue; } @@ -147,9 +141,9 @@ public class ClientIndexer { * @internal */ public void removeClientFromIndex(Client client) { - for(Map>> tagIndices : this.indices.values()){ - for(Map> index : tagIndices.values()){ - for(HashSet clients : index.values()){ + for(Map>> tagIndices : this.indices.values()){ + for(Map> index : tagIndices.values()){ + for(Set clients : index.values()){ /** * Этот тройной цикл не такой страшный, так как мы всего лишь * проходим по всем тегам (их немного), дальше идем по всем значениям в тегах @@ -173,7 +167,7 @@ public class ClientIndexer { * @param indexValue значение в теге * @return список клиентов с заданными значениями */ - public HashSet getClients(Class tagClass, String indexName, Object indexValue) { + public Set getClients(Class tagClass, String indexName, Object indexValue) { if(indexName == null || indexValue == null){ return null; } @@ -181,12 +175,12 @@ public class ClientIndexer { /** * Получение по индексу простое, так как каждое из заданных значений и есть ключ */ - Map>> tagIndices = indices.get(tagClass); + ConcurrentHashMap>> tagIndices = indices.get(tagClass); if (tagIndices == null) { return null; } - Map> index = tagIndices.get(indexName); + ConcurrentHashMap> index = tagIndices.get(indexName); if (index == null) { return null; }