From 984ad3f81a4374a8fe2d55cdec21ba92ab990082 Mon Sep 17 00:00:00 2001 From: Trivuele Date: Sun, 17 Apr 2022 11:00:00 +0000 Subject: [PATCH] Replace RequestStarter throttling with simplier logic The RequestStarter logic was subtly broken in multiple ways: - Bad interaction between rtt and window estimates would cause your node to oscillate between starting way more requests than the network can handle and almost stalling entirely for minutes. The speed difference may be a factor 100x from one minute to another. - Nodes patched with the infamous RequestStarter patches would cause your node to throttle down on number of requests started to their advantage. This could potentially be exploited by an attacker as well. - The window estimation would attempt to throttle the speed to target a certain ratio of requests succeeding without getting dropped due to rejected-overload. This would avoid meltdown of the network, but the target was not hard-coded but dependant on average network speed among other things, in practice ending up allowing 30% of requests to fail. - The window estimation was changed according to an AIMD schedule. This would have encouraged nodes on the network to agree on a speed collectively, but the logic deviated from AIMD in undocumented ways, for example by making the incremental step multiplicative. It is unclear if this would actually cause any agreement on the network. - All code was completely undocumented, had many seemingly arbitrarily chosen constants, and multiple lines of code with no effect at all. - There are other ways to design the estimation of an ideal request starting speed that avoids most of the above problems, but it would still require selecting some arbitrary constants, so not obviously better than replacing all logic altogether with a single constant. The whole thing can be viewed as a single network constant; the number of requests per second and peer we can start to cause an ideal load on the network, assuming distribution of types of requests and idling and busy nodes looks like it does today. The biggest advantage of this method is that it causes a very even starting of requests everywhere in the network, with no oscillating speeding that chokes parts of the space in turns. This may enable faster speeds with fewer rejected-overloads and peer backoffs. There are other advantages with this simple method as well. If a future release does something that improves or worsen rejected-overload ratio or average request completion time, it will show clearly in the stats. The network will not try to conceal the change. The constant was tuned to an empirical value matching todays average request starting speed. This may need finetuning in future releases if rejected-overload situation improves and higher speeds are possible. Made all stats average over whole session, but no persistent. This makes them more useful to judge state of network. === Review note === This is not perfect, because at lower speeds peer count is the logarithm of the speed, so with this change slow peers may be sending more request than right for their bandwidth. But the previous logic was broken, because the static increment was divided by the window size, so it was actually an increase by a fraction of the window size, which is not how AIMD works. Merging even though this might need more tuning, because it is an improvement. - Arne --- .../clients/http/StatisticsToadlet.java | 6 - src/freenet/l10n/freenet.l10n.de.properties | 1 - src/freenet/l10n/freenet.l10n.en.properties | 2 - src/freenet/l10n/freenet.l10n.es.properties | 2 - src/freenet/l10n/freenet.l10n.fa.properties | 1 - src/freenet/l10n/freenet.l10n.fr.properties | 2 - src/freenet/l10n/freenet.l10n.it.properties | 2 - src/freenet/l10n/freenet.l10n.ja.properties | 1 - .../l10n/freenet.l10n.nb-no.properties | 1 - src/freenet/l10n/freenet.l10n.nl.properties | 2 - .../l10n/freenet.l10n.pt-br.properties | 2 - .../l10n/freenet.l10n.pt_PT.properties | 2 - src/freenet/l10n/freenet.l10n.ru.properties | 2 - .../l10n/freenet.l10n.zh-cn.properties | 2 - .../l10n/freenet.l10n.zh-tw.properties | 2 - src/freenet/node/BaseRequestThrottle.java | 20 -- src/freenet/node/NodeClientCore.java | 10 +- src/freenet/node/RequestStarter.java | 20 +- src/freenet/node/RequestStarterGroup.java | 303 +++++++----------- src/freenet/node/ThrottleWindowManager.java | 83 ----- 20 files changed, 127 insertions(+), 339 deletions(-) delete mode 100644 src/freenet/node/BaseRequestThrottle.java delete mode 100644 src/freenet/node/ThrottleWindowManager.java diff --git a/src/freenet/clients/http/StatisticsToadlet.java b/src/freenet/clients/http/StatisticsToadlet.java index eb82ad4ed6e..6dfa4262e06 100644 --- a/src/freenet/clients/http/StatisticsToadlet.java +++ b/src/freenet/clients/http/StatisticsToadlet.java @@ -544,17 +544,11 @@ private void drawLoadBalancingBox(HTMLNode loadStatsInfobox, boolean realTime) { loadStatsInfobox.addChild("div", "class", "infobox-header", "Load limiting "+(realTime ? "RealTime" : "Bulk")); HTMLNode loadStatsContent = loadStatsInfobox.addChild("div", "class", "infobox-content"); RequestStarterGroup starters = core.requestStarters; - double window = starters.getWindow(realTime); - double realWindow = starters.getRealWindow(realTime); HTMLNode loadStatsList = loadStatsContent.addChild("ul"); - loadStatsList.addChild("li", l10n("globalWindow")+": "+window); - loadStatsList.addChild("li", l10n("realGlobalWindow")+": "+realWindow); loadStatsList.addChild("li", starters.statsPageLine(false, false, realTime)); loadStatsList.addChild("li", starters.statsPageLine(true, false, realTime)); loadStatsList.addChild("li", starters.statsPageLine(false, true, realTime)); loadStatsList.addChild("li", starters.statsPageLine(true, true, realTime)); - loadStatsList.addChild("li", starters.diagnosticThrottlesLine(false)); - loadStatsList.addChild("li", starters.diagnosticThrottlesLine(true)); } private void drawNewLoadManagementBox(HTMLNode infobox) { diff --git a/src/freenet/l10n/freenet.l10n.de.properties b/src/freenet/l10n/freenet.l10n.de.properties index 6cb702a901e..c1ddb4708b7 100644 --- a/src/freenet/l10n/freenet.l10n.de.properties +++ b/src/freenet/l10n/freenet.l10n.de.properties @@ -1757,7 +1757,6 @@ StatisticsToadlet.distanceStats=Entfernungsstatistiken StatisticsToadlet.falsePos=Falsch positive StatisticsToadlet.fullTitle=Statistiken StatisticsToadlet.getLogs=Letzte Log-Datei des Knotens abrufen -StatisticsToadlet.globalWindow=Globales Fenster StatisticsToadlet.inputRate=Eingehend: ${rate}/sec (von ${max}/sec) StatisticsToadlet.jobType=Job Typ StatisticsToadlet.jvmInfoTitle=Java-Info diff --git a/src/freenet/l10n/freenet.l10n.en.properties b/src/freenet/l10n/freenet.l10n.en.properties index 46c61baa861..b1313ec5e41 100644 --- a/src/freenet/l10n/freenet.l10n.en.properties +++ b/src/freenet/l10n/freenet.l10n.en.properties @@ -1985,7 +1985,6 @@ StatisticsToadlet.foafBytes=FOAF related: ${total} StatisticsToadlet.fullTitle=Statistics StatisticsToadlet.furthestSuccess=Furthest Success StatisticsToadlet.getLogs=Get latest node's logfile -StatisticsToadlet.globalWindow=Global window StatisticsToadlet.inputRate=Input Rate: ${rate}/s (of ${max}/s) StatisticsToadlet.insertOutput=Insert output (excluding payload): CHK ${chk} SSK ${ssk}. StatisticsToadlet.jobType=Job Type @@ -2017,7 +2016,6 @@ StatisticsToadlet.priority=Priority StatisticsToadlet.PUB_KEY=Pubkey StatisticsToadlet.queuedCount=Queued Count StatisticsToadlet.readRequests=Read-Requests -StatisticsToadlet.realGlobalWindow=Real global window StatisticsToadlet.requestOutput=Request output (excluding payload): CHK ${chk} SSK ${ssk}. StatisticsToadlet.resendBytes=Resent bytes: ${total} (${percent}%) StatisticsToadlet.routingBackoffReason=Routing Backoff Reason diff --git a/src/freenet/l10n/freenet.l10n.es.properties b/src/freenet/l10n/freenet.l10n.es.properties index 79ed3d4b173..fe01882afff 100644 --- a/src/freenet/l10n/freenet.l10n.es.properties +++ b/src/freenet/l10n/freenet.l10n.es.properties @@ -1896,7 +1896,6 @@ StatisticsToadlet.foafBytes=De amigo de un amigo (FOAF): ${total} StatisticsToadlet.fullTitle=Estadísticas StatisticsToadlet.furthestSuccess=Éxito más lejano StatisticsToadlet.getLogs=Ver último fichero de registro (log) -StatisticsToadlet.globalWindow=Ventana global StatisticsToadlet.inputRate=Tasa de entrada: ${rate}/s (de ${max}/s) StatisticsToadlet.insertOutput=Salida de inserciones (excluyendo carga útil): CHK ${chk} SSK ${ssk}. StatisticsToadlet.jobType=Tipo de trabajo @@ -1928,7 +1927,6 @@ StatisticsToadlet.priority=Prioridad StatisticsToadlet.PUB_KEY=Clave pública StatisticsToadlet.queuedCount=En cola StatisticsToadlet.readRequests=Peticiones de lectura -StatisticsToadlet.realGlobalWindow=Ventana global real StatisticsToadlet.requestOutput=Salida de peticiones (excluyendo carga útil): CHK ${chk} SSK ${ssk}. StatisticsToadlet.resendBytes=Bytes reenviados: ${total} (${percent}%) StatisticsToadlet.routingBackoffReason=Motivo de desasistencia de enrutamiento diff --git a/src/freenet/l10n/freenet.l10n.fa.properties b/src/freenet/l10n/freenet.l10n.fa.properties index e0bb9fd526c..967a5365dd5 100644 --- a/src/freenet/l10n/freenet.l10n.fa.properties +++ b/src/freenet/l10n/freenet.l10n.fa.properties @@ -803,7 +803,6 @@ StatisticsToadlet.clientRequesters.priorityClass=کلاس اولویت StatisticsToadlet.clientRequesters.uri=آدرس اینترنتی StatisticsToadlet.datasize=اندازه داده StatisticsToadlet.fullTitle=آمار -StatisticsToadlet.globalWindow=پنجره سراسری StatisticsToadlet.jvmInfoTitle=نوع جاوا StatisticsToadlet.keys=کلید ها StatisticsToadlet.maxTotalPeers=همتایان بیشینه diff --git a/src/freenet/l10n/freenet.l10n.fr.properties b/src/freenet/l10n/freenet.l10n.fr.properties index 1a90d6b7659..25b7e2c5b98 100644 --- a/src/freenet/l10n/freenet.l10n.fr.properties +++ b/src/freenet/l10n/freenet.l10n.fr.properties @@ -1896,7 +1896,6 @@ StatisticsToadlet.foafBytes=Connexe aux amis d’un ami : ${total} StatisticsToadlet.fullTitle=Statistiques StatisticsToadlet.furthestSuccess=Succès le plus éloigné StatisticsToadlet.getLogs=Obtenir le dernier journal du nœud -StatisticsToadlet.globalWindow=Fenêtre globale StatisticsToadlet.inputRate=Taux d’entrée : ${rate}/s (sur ${max}/s) StatisticsToadlet.insertOutput=Sortie d’insertion (excluant la charge utile) : CHK ${chk} SSK ${ssk}. StatisticsToadlet.jobType=Type de travail @@ -1928,7 +1927,6 @@ StatisticsToadlet.priority=Priorité StatisticsToadlet.PUB_KEY=Clé publique StatisticsToadlet.queuedCount=Compteur de la file d’attente StatisticsToadlet.readRequests=Requêtes de lecture -StatisticsToadlet.realGlobalWindow=Fenêtre globale réelle StatisticsToadlet.requestOutput=Sortie des requêtes (excluant la charge utile) : CHK ${chk} SSK ${ssk}. StatisticsToadlet.resendBytes=Octets renvoyés : ${total} (${percent} %) StatisticsToadlet.routingBackoffReason=Raison de la temporisation (backoff) du routage diff --git a/src/freenet/l10n/freenet.l10n.it.properties b/src/freenet/l10n/freenet.l10n.it.properties index d906788a81b..1a739d27caf 100644 --- a/src/freenet/l10n/freenet.l10n.it.properties +++ b/src/freenet/l10n/freenet.l10n.it.properties @@ -1741,7 +1741,6 @@ StatisticsToadlet.falsePos=Falsi positivi StatisticsToadlet.fullTitle=Statistiche StatisticsToadlet.furthestSuccess=Successo più lontano StatisticsToadlet.getLogs=Prendi l'ultimo file di registro del nodo -StatisticsToadlet.globalWindow=Finestra globale StatisticsToadlet.inputRate=Tasso di input: ${rate}/s (di ${max}/s) StatisticsToadlet.insertOutput=Output degli inserimenti (escludendo il carico utile): CHK ${chk} SSK ${ssk} StatisticsToadlet.jobType=Tipo di lavoro @@ -1770,7 +1769,6 @@ StatisticsToadlet.priority=Priorità StatisticsToadlet.PUB_KEY=Pubkey (chiave pubblica) StatisticsToadlet.queuedCount=Conteggio accodato StatisticsToadlet.readRequests=Richieste di lettura -StatisticsToadlet.realGlobalWindow=Finestra reale globale StatisticsToadlet.requestOutput=Output delle richieste (carico utile escluso): CHK ${chk} SSK ${ssk}. StatisticsToadlet.resendBytes=Bytes rispediti: ${total} (${percent}%) StatisticsToadlet.routingBackoffReason=Motivo del recesso dell'instradamento diff --git a/src/freenet/l10n/freenet.l10n.ja.properties b/src/freenet/l10n/freenet.l10n.ja.properties index 7f78c526b9e..3c0e43c6472 100644 --- a/src/freenet/l10n/freenet.l10n.ja.properties +++ b/src/freenet/l10n/freenet.l10n.ja.properties @@ -1200,7 +1200,6 @@ StatisticsToadlet.foafBytes=友達の友達関係: ${total} StatisticsToadlet.fullTitle=統計 StatisticsToadlet.furthestSuccess=もっとも遠い成功 StatisticsToadlet.getLogs=ノードの最新のログファイルを入手 -StatisticsToadlet.globalWindow=グローバルウィンドウ StatisticsToadlet.inputRate=入力レート: ${rate}/s (of ${max}/s) StatisticsToadlet.insertOutput=インサート出力 (ペイロードを含まず): CHK ${chk} SSK ${ssk}. StatisticsToadlet.jobType=ジョブタイプ diff --git a/src/freenet/l10n/freenet.l10n.nb-no.properties b/src/freenet/l10n/freenet.l10n.nb-no.properties index 112172eeefa..7b76b14d8e8 100644 --- a/src/freenet/l10n/freenet.l10n.nb-no.properties +++ b/src/freenet/l10n/freenet.l10n.nb-no.properties @@ -1465,7 +1465,6 @@ StatisticsToadlet.datastore=Datalager StatisticsToadlet.databaseJobsByPriority=Database-jobber StatisticsToadlet.distanceStats=Distansestatistikk StatisticsToadlet.fullTitle=Statistikk -StatisticsToadlet.globalWindow=Hovedvindu StatisticsToadlet.jobType=Jobb-type StatisticsToadlet.jvmInfoTitle=JVM-info StatisticsToadlet.jvmName=Java VM-navn: ${name} diff --git a/src/freenet/l10n/freenet.l10n.nl.properties b/src/freenet/l10n/freenet.l10n.nl.properties index 2a3d2c1185b..d80b42ef34b 100644 --- a/src/freenet/l10n/freenet.l10n.nl.properties +++ b/src/freenet/l10n/freenet.l10n.nl.properties @@ -1838,7 +1838,6 @@ StatisticsToadlet.foafBytes=FOAF gerelateerd: ${total} StatisticsToadlet.fullTitle=Statistieken StatisticsToadlet.furthestSuccess=Verste succes StatisticsToadlet.getLogs=Haal het meest recente logbestand op -StatisticsToadlet.globalWindow=Globale venster StatisticsToadlet.inputRate=Huidig inkomend verbruik: ${rate}/s (max ${max}/s) StatisticsToadlet.insertOutput=Uitgaand invoegingenverkeer (exclusief payload): CHK ${chk} SSK ${ssk}. StatisticsToadlet.jobType=Taak type @@ -1868,7 +1867,6 @@ StatisticsToadlet.peerStatsTitle=Peer-statistieken StatisticsToadlet.priority=Prioriteit StatisticsToadlet.queuedCount=Aantal queued StatisticsToadlet.readRequests=Leesverzoeken -StatisticsToadlet.realGlobalWindow=Ware globale venster StatisticsToadlet.requestOutput=Uitgaande verzoeken (exclusief payload): CHK ${chk} SSK ${ssk}. StatisticsToadlet.resendBytes=Opnieuw verstuurde bytes: ${total} StatisticsToadlet.routingBackoffReason=Routering terugtreedreden diff --git a/src/freenet/l10n/freenet.l10n.pt-br.properties b/src/freenet/l10n/freenet.l10n.pt-br.properties index 4660d3b287e..c3669ec8b6d 100644 --- a/src/freenet/l10n/freenet.l10n.pt-br.properties +++ b/src/freenet/l10n/freenet.l10n.pt-br.properties @@ -1739,7 +1739,6 @@ StatisticsToadlet.foafBytes=Relacionado a amigos de amigos: ${total} StatisticsToadlet.fullTitle=Estatísticas StatisticsToadlet.furthestSuccess=Sucesso mais distante StatisticsToadlet.getLogs=Obter o último arquivo de registros do nó -StatisticsToadlet.globalWindow=Janela global StatisticsToadlet.inputRate=Taxa de entrada: ${rate}/s (de ${max}/s) StatisticsToadlet.jobType=Tipo de tarefa StatisticsToadlet.jvmInfoTitle=Informações da Máquina Virtual Java @@ -1765,7 +1764,6 @@ StatisticsToadlet.peerStatsTitle=Estatísticas de nós StatisticsToadlet.priority=Prioridade StatisticsToadlet.PUB_KEY=Chavepub StatisticsToadlet.readRequests=Pedidos de leitura -StatisticsToadlet.realGlobalWindow=Janela global real StatisticsToadlet.resendBytes=Bytes reenviados: ${total} (${percent}%) StatisticsToadlet.routingDisabled=Sem tráfego de roteamento (estamos conectados ao nó, mas há recusa, dele ou nossa, em encaminhar tráfego) StatisticsToadlet.routingDisabledShort=Sem rotear tráfego diff --git a/src/freenet/l10n/freenet.l10n.pt_PT.properties b/src/freenet/l10n/freenet.l10n.pt_PT.properties index 88a6c58f90b..9a0a32ccf22 100644 --- a/src/freenet/l10n/freenet.l10n.pt_PT.properties +++ b/src/freenet/l10n/freenet.l10n.pt_PT.properties @@ -663,7 +663,6 @@ StatisticsToadlet.clientRequesters.priorityClass=Classe da Prioridade StatisticsToadlet.clientRequesters.uri=URL StatisticsToadlet.datasize=Tamanho dos Dados StatisticsToadlet.fullTitle=Estatísticas -StatisticsToadlet.globalWindow=Janela global StatisticsToadlet.jobType=Tipo de Trabalho StatisticsToadlet.jvmInfoTitle=Informação Java StatisticsToadlet.keys=Chaves @@ -672,7 +671,6 @@ StatisticsToadlet.osName=Nome do SO: ${name} StatisticsToadlet.osVersion=Versão do SO: ${version} StatisticsToadlet.priority=Prioridade StatisticsToadlet.PUB_KEY=Chave pública -StatisticsToadlet.realGlobalWindow=Janela global real StatisticsToadlet.running=Em execução StatisticsToadlet.seedTableConnections=Ligado StatisticsToadlet.seedTableAnnouncements=Anunciado diff --git a/src/freenet/l10n/freenet.l10n.ru.properties b/src/freenet/l10n/freenet.l10n.ru.properties index 5686a0e97cf..5c97f9df18a 100644 --- a/src/freenet/l10n/freenet.l10n.ru.properties +++ b/src/freenet/l10n/freenet.l10n.ru.properties @@ -1634,7 +1634,6 @@ StatisticsToadlet.foafBytes=Обмен FOAF: ${total} StatisticsToadlet.fullTitle=Статистика StatisticsToadlet.furthestSuccess=Самое дальнее попадание StatisticsToadlet.getLogs=Получить последний лог-файл узла -StatisticsToadlet.globalWindow=«Глобальное окно» программы StatisticsToadlet.inputRate=Скорость загрузки: ${rate}/с (из ${max}/с) StatisticsToadlet.insertOutput=Исх. трафик выгрузок (только служ. информация): CHK ${chk} SSK ${ssk}. StatisticsToadlet.jobType=Тип работ @@ -1665,7 +1664,6 @@ StatisticsToadlet.peerStatsTitle=Соседние узлы StatisticsToadlet.priority=Приоритет StatisticsToadlet.queuedCount=В очереди StatisticsToadlet.readRequests=Запросы на чтение -StatisticsToadlet.realGlobalWindow=Действительное «глобальное окно» программы StatisticsToadlet.requestOutput=Исх. трафик ответов (только служ. информация): CHK ${chk} SSK ${ssk}. StatisticsToadlet.resendBytes=Отправлено повторно: ${total} (${percent}%) StatisticsToadlet.routingBackoffReason=Причины отказа в перенаправлении diff --git a/src/freenet/l10n/freenet.l10n.zh-cn.properties b/src/freenet/l10n/freenet.l10n.zh-cn.properties index c02b2af507c..6717ead569d 100644 --- a/src/freenet/l10n/freenet.l10n.zh-cn.properties +++ b/src/freenet/l10n/freenet.l10n.zh-cn.properties @@ -1906,7 +1906,6 @@ StatisticsToadlet.foafBytes=FOAF 相关: ${total} StatisticsToadlet.fullTitle=统计数据 StatisticsToadlet.furthestSuccess=最远成功距离 StatisticsToadlet.getLogs=获取最近的节点日志 -StatisticsToadlet.globalWindow=全局窗口 StatisticsToadlet.inputRate=输入速率: ${rate}/秒 (上限 ${max}/秒) StatisticsToadlet.insertOutput=插入输出 (排除有效载荷): CHK ${chk} SSK ${ssk} StatisticsToadlet.jobType=工作类型 @@ -1938,7 +1937,6 @@ StatisticsToadlet.priority=优先级 StatisticsToadlet.PUB_KEY=公钥 StatisticsToadlet.queuedCount=队列计数 StatisticsToadlet.readRequests=读取请求 -StatisticsToadlet.realGlobalWindow=实时全局窗口 StatisticsToadlet.requestOutput=请求输出 (排除有效载荷): CHK ${chk} SSK ${ssk} StatisticsToadlet.resendBytes=重新发送字节: ${total} StatisticsToadlet.routingBackoffReason=路由退避原因 diff --git a/src/freenet/l10n/freenet.l10n.zh-tw.properties b/src/freenet/l10n/freenet.l10n.zh-tw.properties index 0df26cb3b09..5698c9441bf 100644 --- a/src/freenet/l10n/freenet.l10n.zh-tw.properties +++ b/src/freenet/l10n/freenet.l10n.zh-tw.properties @@ -1884,7 +1884,6 @@ StatisticsToadlet.foafBytes=FOAF 相關: ${total} StatisticsToadlet.fullTitle=統計資料 StatisticsToadlet.furthestSuccess=最遠成功距離 StatisticsToadlet.getLogs=下載節點的最新日誌 -StatisticsToadlet.globalWindow=全域視窗 StatisticsToadlet.inputRate=輸入速率: 每秒 ${rate} (上限每秒 ${max}) StatisticsToadlet.insertOutput=入鍵輸出(不包含載物): CHK ${chk} SSK ${ssk}. StatisticsToadlet.jobType=工作類型 @@ -1916,7 +1915,6 @@ StatisticsToadlet.priority=優先度 StatisticsToadlet.PUB_KEY=公鑰 StatisticsToadlet.queuedCount=佇列計數 StatisticsToadlet.readRequests=讀取請求 -StatisticsToadlet.realGlobalWindow=實時全域視窗 StatisticsToadlet.requestOutput=請求輸出(不包含載物): CHK ${chk} SSK ${ssk}. StatisticsToadlet.resendBytes=重送位元組: ${total} StatisticsToadlet.routingBackoffReason=路由退避原因 diff --git a/src/freenet/node/BaseRequestThrottle.java b/src/freenet/node/BaseRequestThrottle.java deleted file mode 100644 index 682471f1845..00000000000 --- a/src/freenet/node/BaseRequestThrottle.java +++ /dev/null @@ -1,20 +0,0 @@ -/* This code is part of Freenet. It is distributed under the GNU General - * Public License, version 2 (or at your option any later version). See - * http://www.gnu.org/ for further details of the GPL. */ -package freenet.node; - -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.MINUTES; - -public interface BaseRequestThrottle { - - public static final long DEFAULT_DELAY = MILLISECONDS.toMillis(200); - static final long MAX_DELAY = MINUTES.toMillis(5); - static final long MIN_DELAY = MILLISECONDS.toMillis(20); - - /** - * Get the current inter-request delay. - */ - public abstract long getDelay(); - -} \ No newline at end of file diff --git a/src/freenet/node/NodeClientCore.java b/src/freenet/node/NodeClientCore.java index 2ec4f841f2c..249f8923240 100644 --- a/src/freenet/node/NodeClientCore.java +++ b/src/freenet/node/NodeClientCore.java @@ -1210,7 +1210,7 @@ public void onRequestSenderFinished(int status, boolean fromOfferedKey, RequestS if(!rejectedOverload) requestStarters.requestCompleted(isSSK, false, key, realTimeFlag); // Count towards RTT even if got a RejectedOverload - but not if timed out. - requestStarters.getThrottle(isSSK, false, realTimeFlag).successfulCompletion(rtt); + requestStarters.getStats(isSSK, false, realTimeFlag).addRTT(rtt); if(isSSK) { node.nodeStats.reportSSKOutcome(rtt, status == RequestSender.SUCCESS, realTimeFlag); } else { @@ -1421,7 +1421,7 @@ ClientCHKBlock realGetCHK(ClientCHK key, boolean localOnly, boolean ignoreStore, if(!rejectedOverload) requestStarters.requestCompleted(false, false, key.getNodeKey(true), realTimeFlag); // Count towards RTT even if got a RejectedOverload - but not if timed out. - requestStarters.getThrottle(false, false, realTimeFlag).successfulCompletion(rtt); + requestStarters.getStats(false, false, realTimeFlag).addRTT(rtt); node.nodeStats.reportCHKOutcome(rtt, status == RequestSender.SUCCESS, targetLocation, realTimeFlag); if(status == RequestSender.SUCCESS) { Logger.minor(this, "Successful CHK fetch took "+rtt); @@ -1542,7 +1542,7 @@ ClientSSKBlock realGetSSK(ClientSSK key, boolean localOnly, boolean ignoreStore, if(!rejectedOverload) requestStarters.requestCompleted(true, false, key.getNodeKey(true), realTimeFlag); // Count towards RTT even if got a RejectedOverload - but not if timed out. - requestStarters.getThrottle(true, false, realTimeFlag).successfulCompletion(rtt); + requestStarters.getStats(true, false, realTimeFlag).addRTT(rtt); node.nodeStats.reportSSKOutcome(rtt, status == RequestSender.SUCCESS, realTimeFlag); } @@ -1667,7 +1667,7 @@ public void realPutCHK(CHKBlock block, boolean canWriteClientCache, boolean fork long len = endTime - startTime; // RejectedOverload requests count towards RTT (timed out ones don't). - requestStarters.getThrottle(false, true, realTimeFlag).successfulCompletion(len); + requestStarters.getStats(false, true, realTimeFlag).addRTT(len); requestStarters.requestCompleted(false, true, block.getKey(), realTimeFlag); } @@ -1786,7 +1786,7 @@ public void realPutSSK(SSKBlock block, boolean canWriteClientCache, boolean fork long endTime = System.currentTimeMillis(); long rtt = endTime - startTime; requestStarters.requestCompleted(true, true, block.getKey(), realTimeFlag); - requestStarters.getThrottle(true, true, realTimeFlag).successfulCompletion(rtt); + requestStarters.getStats(true, true, realTimeFlag).addRTT(rtt); } int status = is.getStatus(); diff --git a/src/freenet/node/RequestStarter.java b/src/freenet/node/RequestStarter.java index 613600bb9cf..0c735e8c484 100644 --- a/src/freenet/node/RequestStarter.java +++ b/src/freenet/node/RequestStarter.java @@ -61,7 +61,6 @@ public static boolean isValidPriorityClass(int prio) { return !((prio < MAXIMUM_PRIORITY_CLASS) || (prio > PAUSED_PRIORITY_CLASS)); } - final BaseRequestThrottle throttle; final RunningAverage averageInputBytesPerRequest; final RunningAverage averageOutputBytesPerRequest; RequestScheduler sched; @@ -72,12 +71,16 @@ public static boolean isValidPriorityClass(int prio) { final boolean realTime; static final int MAX_WAITING_FOR_SLOTS = 50; - - public RequestStarter(NodeClientCore node, BaseRequestThrottle throttle, String name, - RunningAverage averageOutputBytesPerRequest, RunningAverage averageInputBytesPerRequest, boolean isInsert, boolean isSSK, boolean realTime) { + + /** Throttle speed at which local requests are started */ + private final long DELAY_MS_PER_PEER = 5400; // 655 MB/hour if 30 peers + + public RequestStarter(NodeClientCore node, String name, + RunningAverage averageOutputBytesPerRequest, + RunningAverage averageInputBytesPerRequest, + boolean isInsert, boolean isSSK, boolean realTime) { this.core = node; this.stats = core.nodeStats; - this.throttle = throttle; this.name = name + (realTime ? " (realtime)" : " (bulk)"); this.averageOutputBytesPerRequest = averageOutputBytesPerRequest; this.averageInputBytesPerRequest = averageInputBytesPerRequest; @@ -127,9 +130,10 @@ void realRun() { if(logMINOR) Logger.minor(this, "Running "+req+" priority "+req.getPriority()); if(!req.localRequestOnly) { // Wait - long delay; - delay = throttle.getDelay(); - if(logMINOR) Logger.minor(this, "Delay="+delay+" from "+throttle); + long numPeers = core.node.peers.countNonBackedOffPeers(realTime); + if (numPeers < 1) numPeers = 1; + long delay = DELAY_MS_PER_PEER / numPeers; + if(logMINOR) Logger.minor(this, "Delay="+delay); long sleepUntil = cycleTime + delay; long now; do { diff --git a/src/freenet/node/RequestStarterGroup.java b/src/freenet/node/RequestStarterGroup.java index eda7ab9be7b..57f0b528956 100644 --- a/src/freenet/node/RequestStarterGroup.java +++ b/src/freenet/node/RequestStarterGroup.java @@ -1,6 +1,7 @@ /* This code is part of Freenet. It is distributed under the GNU General * Public License, version 2 (or at your option any later version). See * http://www.gnu.org/ for further details of the GPL. */ + package freenet.node; import freenet.client.async.ClientContext; @@ -17,9 +18,6 @@ import freenet.support.SimpleFieldSet; import freenet.support.TimeUtil; import freenet.support.api.StringCallback; -import freenet.support.math.BootstrappingDecayingRunningAverage; - -import static java.util.concurrent.TimeUnit.MINUTES; public class RequestStarterGroup { private static volatile boolean logMINOR; @@ -33,29 +31,23 @@ public void shouldUpdate(){ }); } - private final ThrottleWindowManager throttleWindowBulk; - private final ThrottleWindowManager throttleWindowRT; - // These are for diagnostic purposes - private final ThrottleWindowManager throttleWindowCHK; - private final ThrottleWindowManager throttleWindowSSK; - private final ThrottleWindowManager throttleWindowInsert; - private final ThrottleWindowManager throttleWindowRequest; - final MyRequestThrottle chkRequestThrottleBulk; + final MyStats sskInsertStatsRT; + final MyStats sskRequestStatsRT; + final MyStats chkInsertStatsRT; + final MyStats chkRequestStatsRT; + final MyStats sskInsertStatsBulk; + final MyStats sskRequestStatsBulk; + final MyStats chkInsertStatsBulk; + final MyStats chkRequestStatsBulk; + final RequestStarter chkRequestStarterBulk; - final MyRequestThrottle chkInsertThrottleBulk; final RequestStarter chkInsertStarterBulk; - final MyRequestThrottle sskRequestThrottleBulk; final RequestStarter sskRequestStarterBulk; - final MyRequestThrottle sskInsertThrottleBulk; final RequestStarter sskInsertStarterBulk; - final MyRequestThrottle chkRequestThrottleRT; final RequestStarter chkRequestStarterRT; - final MyRequestThrottle chkInsertThrottleRT; final RequestStarter chkInsertStarterRT; - final MyRequestThrottle sskRequestThrottleRT; final RequestStarter sskRequestStarterRT; - final MyRequestThrottle sskInsertThrottleRT; final RequestStarter sskInsertStarterRT; public final ClientRequestScheduler chkFetchSchedulerBulk; @@ -71,18 +63,18 @@ public void shouldUpdate(){ RequestStarterGroup(Node node, NodeClientCore core, int portNumber, RandomSource random, Config config, SimpleFieldSet fs, ClientContext ctx) throws InvalidConfigValueException { SubConfig schedulerConfig = config.createSubConfig("node.scheduler"); this.stats = core.nodeStats; + + sskInsertStatsRT = new MyStats(); + sskRequestStatsRT = new MyStats(); + chkInsertStatsRT = new MyStats(); + chkRequestStatsRT = new MyStats(); + sskInsertStatsBulk = new MyStats(); + sskRequestStatsBulk = new MyStats(); + chkInsertStatsBulk = new MyStats(); + chkRequestStatsBulk = new MyStats(); - throttleWindowBulk = new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindow"), node); - throttleWindowRT = new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowRT"), node); - - throttleWindowCHK = new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowCHK"), node); - throttleWindowSSK = new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowSSK"), node); - throttleWindowInsert = new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowInsert"), node); - throttleWindowRequest = new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowRequest"), node); - chkRequestThrottleBulk = new MyRequestThrottle(5000, "CHK Request", fs == null ? null : fs.subset("CHKRequestThrottle"), 32768, false); - chkRequestThrottleRT = new MyRequestThrottle(5000, "CHK Request (RT)", fs == null ? null : fs.subset("CHKRequestThrottleRT"), 32768, true); - chkRequestStarterBulk = new RequestStarter(core, chkRequestThrottleBulk, "CHK Request starter ("+portNumber+ ')', stats.localChkFetchBytesSentAverage, stats.localChkFetchBytesReceivedAverage, false, false, false); - chkRequestStarterRT = new RequestStarter(core, chkRequestThrottleRT, "CHK Request starter ("+portNumber+ ')', stats.localChkFetchBytesSentAverage, stats.localChkFetchBytesReceivedAverage, false, false, true); + chkRequestStarterBulk = new RequestStarter(core, "CHK Request starter ("+portNumber+ ')', stats.localChkFetchBytesSentAverage, stats.localChkFetchBytesReceivedAverage, false, false, false); + chkRequestStarterRT = new RequestStarter(core, "CHK Request starter ("+portNumber+ ')', stats.localChkFetchBytesSentAverage, stats.localChkFetchBytesReceivedAverage, false, false, true); chkFetchSchedulerBulk = new ClientRequestScheduler(false, false, false, random, chkRequestStarterBulk, node, core, "CHKrequester", ctx); chkFetchSchedulerRT = new ClientRequestScheduler(false, false, true, random, chkRequestStarterRT, node, core, "CHKrequester", ctx); chkRequestStarterBulk.setScheduler(chkFetchSchedulerBulk); @@ -90,12 +82,8 @@ public void shouldUpdate(){ registerSchedulerConfig(schedulerConfig, "CHKrequester", chkFetchSchedulerBulk, chkFetchSchedulerRT, false, false); - //insertThrottle = new ChainedRequestThrottle(10000, 2.0F, requestThrottle); - // FIXME reenable the above - chkInsertThrottleBulk = new MyRequestThrottle(20000, "CHK Insert", fs == null ? null : fs.subset("CHKInsertThrottle"), 32768, false); - chkInsertThrottleRT = new MyRequestThrottle(20000, "CHK Insert (RT)", fs == null ? null : fs.subset("CHKInsertThrottleRT"), 32768, true); - chkInsertStarterBulk = new RequestStarter(core, chkInsertThrottleBulk, "CHK Insert starter ("+portNumber+ ')', stats.localChkInsertBytesSentAverage, stats.localChkInsertBytesReceivedAverage, true, false, false); - chkInsertStarterRT = new RequestStarter(core, chkInsertThrottleRT, "CHK Insert starter ("+portNumber+ ')', stats.localChkInsertBytesSentAverage, stats.localChkInsertBytesReceivedAverage, true, false, true); + chkInsertStarterBulk = new RequestStarter(core, "CHK Insert starter ("+portNumber+ ')', stats.localChkInsertBytesSentAverage, stats.localChkInsertBytesReceivedAverage, true, false, false); + chkInsertStarterRT = new RequestStarter(core, "CHK Insert starter ("+portNumber+ ')', stats.localChkInsertBytesSentAverage, stats.localChkInsertBytesReceivedAverage, true, false, true); chkPutSchedulerBulk = new ClientRequestScheduler(true, false, false, random, chkInsertStarterBulk, node, core, "CHKinserter", ctx); chkPutSchedulerRT = new ClientRequestScheduler(true, false, true, random, chkInsertStarterRT, node, core, "CHKinserter", ctx); chkInsertStarterBulk.setScheduler(chkPutSchedulerBulk); @@ -103,10 +91,8 @@ public void shouldUpdate(){ registerSchedulerConfig(schedulerConfig, "CHKinserter", chkPutSchedulerBulk, chkPutSchedulerRT, false, true); - sskRequestThrottleBulk = new MyRequestThrottle(5000, "SSK Request", fs == null ? null : fs.subset("SSKRequestThrottle"), 1024, false); - sskRequestThrottleRT = new MyRequestThrottle(5000, "SSK Request (RT)", fs == null ? null : fs.subset("SSKRequestThrottleRT"), 1024, true); - sskRequestStarterBulk = new RequestStarter(core, sskRequestThrottleBulk, "SSK Request starter ("+portNumber+ ')', stats.localSskFetchBytesSentAverage, stats.localSskFetchBytesReceivedAverage, false, true, false); - sskRequestStarterRT = new RequestStarter(core, sskRequestThrottleRT, "SSK Request starter ("+portNumber+ ')', stats.localSskFetchBytesSentAverage, stats.localSskFetchBytesReceivedAverage, false, true, true); + sskRequestStarterBulk = new RequestStarter(core, "SSK Request starter ("+portNumber+ ')', stats.localSskFetchBytesSentAverage, stats.localSskFetchBytesReceivedAverage, false, true, false); + sskRequestStarterRT = new RequestStarter(core, "SSK Request starter ("+portNumber+ ')', stats.localSskFetchBytesSentAverage, stats.localSskFetchBytesReceivedAverage, false, true, true); sskFetchSchedulerBulk = new ClientRequestScheduler(false, true, false, random, sskRequestStarterBulk, node, core, "SSKrequester", ctx); sskFetchSchedulerRT = new ClientRequestScheduler(false, true, true, random, sskRequestStarterRT, node, core, "SSKrequester", ctx); sskRequestStarterBulk.setScheduler(sskFetchSchedulerBulk); @@ -114,12 +100,8 @@ public void shouldUpdate(){ registerSchedulerConfig(schedulerConfig, "SSKrequester", sskFetchSchedulerBulk, sskFetchSchedulerRT, true, false); - //insertThrottle = new ChainedRequestThrottle(10000, 2.0F, requestThrottle); - // FIXME reenable the above - sskInsertThrottleBulk = new MyRequestThrottle(20000, "SSK Insert", fs == null ? null : fs.subset("SSKInsertThrottle"), 1024, false); - sskInsertThrottleRT = new MyRequestThrottle(20000, "SSK Insert", fs == null ? null : fs.subset("SSKInsertThrottleRT"), 1024, true); - sskInsertStarterBulk = new RequestStarter(core, sskInsertThrottleBulk, "SSK Insert starter ("+portNumber+ ')', stats.localSskInsertBytesSentAverage, stats.localSskFetchBytesReceivedAverage, true, true, false); - sskInsertStarterRT = new RequestStarter(core, sskInsertThrottleRT, "SSK Insert starter ("+portNumber+ ')', stats.localSskInsertBytesSentAverage, stats.localSskFetchBytesReceivedAverage, true, true, true); + sskInsertStarterBulk = new RequestStarter(core, "SSK Insert starter ("+portNumber+ ')', stats.localSskInsertBytesSentAverage, stats.localSskFetchBytesReceivedAverage, true, true, false); + sskInsertStarterRT = new RequestStarter(core, "SSK Insert starter ("+portNumber+ ')', stats.localSskInsertBytesSentAverage, stats.localSskFetchBytesReceivedAverage, true, true, true); sskPutSchedulerBulk = new ClientRequestScheduler(true, true, false, random, sskInsertStarterBulk, node, core, "SSKinserter", ctx); sskPutSchedulerRT = new ClientRequestScheduler(true, true, true, random, sskInsertStarterRT, node, core, "SSKinserter", ctx); sskInsertStarterBulk.setScheduler(sskPutSchedulerBulk); @@ -151,63 +133,6 @@ public void start() { sskRequestStarterBulk.start(); sskInsertStarterBulk.start(); } - - public class MyRequestThrottle implements BaseRequestThrottle { - private final BootstrappingDecayingRunningAverage roundTripTime; - /** Data size for purposes of getRate() */ - private final int size; - private final boolean realTime; - - public MyRequestThrottle(int rtt, String string, SimpleFieldSet fs, int size, boolean realTime) { - roundTripTime = new BootstrappingDecayingRunningAverage(rtt, 10, MINUTES.toMillis(5), 10, fs == null ? null : fs.subset("RoundTripTime")); - this.size = size; - this.realTime = realTime; - } - - @Override - public synchronized long getDelay() { - double rtt = roundTripTime.currentValue(); - double winSizeForMinPacketDelay = rtt / MIN_DELAY; - double _simulatedWindowSize = getThrottleWindow().currentValue(realTime); - if (_simulatedWindowSize > winSizeForMinPacketDelay) { - _simulatedWindowSize = winSizeForMinPacketDelay; - } - if (_simulatedWindowSize < 1.0) { - _simulatedWindowSize = 1.0F; - } - // return (long) (_roundTripTime / _simulatedWindowSize); - return Math.max(MIN_DELAY, Math.min((long) (rtt / _simulatedWindowSize), MAX_DELAY)); - } - - private ThrottleWindowManager getThrottleWindow() { - return RequestStarterGroup.this.getThrottleWindow(realTime); - } - - public synchronized void successfulCompletion(long rtt) { - roundTripTime.report(Math.max(rtt, 10)); - if(logMINOR) - Logger.minor(this, "Reported successful completion: "+rtt+" on "+this+" avg "+roundTripTime.currentValue()); - } - - @Override - public String toString() { - return "rtt: "+roundTripTime.currentValue()+" _s="+getThrottleWindow().currentValue(realTime)+" RT="+realTime; - } - - public SimpleFieldSet exportFieldSet() { - SimpleFieldSet fs = new SimpleFieldSet(false); - fs.put("RoundTripTime", roundTripTime.exportFieldSet(false)); - return fs; - } - - public double getRTT() { - return roundTripTime.currentValue(); - } - - public long getRate() { - return (long) ((1000.0 / getDelay()) * size); - } - } public static class PrioritySchedulerCallback extends StringCallback implements EnumerableOptionCallback { ClientRequestScheduler csRT; @@ -249,22 +174,79 @@ public String[] getPossibleValues() { } } - public ThrottleWindowManager getThrottleWindow(boolean realTime) { - if(realTime) return throttleWindowRT; - else return throttleWindowBulk; + public class MyStats { + long totalTime; + long totalTimeRequests; + + long droppedRequests; + long totalRequests; + + public MyStats() { + totalTime = 0; + totalRequests = 0; + droppedRequests = 0; + } + + public synchronized void addRTT(long rtt) { + totalTime += rtt; + totalTimeRequests++; + } + + public synchronized void requestCompleted() { + totalRequests++; + } + + public synchronized void rejectedOverload() { + droppedRequests++; + totalRequests++; + } + + public synchronized long getRTT() { + return totalTime / Math.max(1, totalTimeRequests); + } + + public synchronized float getDroppedRatio() { + return (float) droppedRequests / + (float) Math.max(1, totalRequests); + } + + public synchronized long getDropped() { + return droppedRequests; + } + + public synchronized long getTotal() { + return totalRequests; + } } + public MyStats getStats(boolean isSSK, boolean isInsert, boolean realTime) { + if (realTime) { + if (isSSK) { + if (isInsert) return sskInsertStatsRT; + else return sskRequestStatsRT; + } else { + if (isInsert) return chkInsertStatsRT; + else return chkRequestStatsRT; + } + } else { + if (isSSK) { + if (isInsert) return sskInsertStatsBulk; + else return sskRequestStatsBulk; + } else { + if (isInsert) return chkInsertStatsBulk; + else return chkRequestStatsBulk; + } + } + } + + public void requestCompleted(boolean isSSK, boolean isInsert, Key key, boolean realTime) { - getThrottleWindow(realTime).requestCompleted(); - (isSSK ? throttleWindowSSK : throttleWindowCHK).requestCompleted(); - (isInsert ? throttleWindowInsert : throttleWindowRequest).requestCompleted(); + getStats(isSSK, isInsert, realTime).requestCompleted(); stats.reportOutgoingRequestLocation(key.toNormalizedDouble()); } public void rejectedOverload(boolean isSSK, boolean isInsert, boolean realTime) { - getThrottleWindow(realTime).rejectedOverload(); - (isSSK ? throttleWindowSSK : throttleWindowCHK).rejectedOverload(); - (isInsert ? throttleWindowInsert : throttleWindowRequest).rejectedOverload(); + getStats(isSSK, isInsert, realTime).rejectedOverload(); } /** @@ -272,91 +254,26 @@ public void rejectedOverload(boolean isSSK, boolean isInsert, boolean realTime) */ SimpleFieldSet persistToFieldSet() { SimpleFieldSet fs = new SimpleFieldSet(false); - fs.put("ThrottleWindow", throttleWindowBulk.exportFieldSet(false)); - fs.put("ThrottleWindowRT", throttleWindowRT.exportFieldSet(false)); - fs.put("ThrottleWindowCHK", throttleWindowCHK.exportFieldSet(false)); - fs.put("ThrottleWindowSSK", throttleWindowCHK.exportFieldSet(false)); - fs.put("CHKRequestThrottle", chkRequestThrottleBulk.exportFieldSet()); - fs.put("SSKRequestThrottle", sskRequestThrottleBulk.exportFieldSet()); - fs.put("CHKInsertThrottle", chkInsertThrottleBulk.exportFieldSet()); - fs.put("SSKInsertThrottle", sskInsertThrottleBulk.exportFieldSet()); - fs.put("CHKRequestThrottleRT", chkRequestThrottleRT.exportFieldSet()); - fs.put("SSKRequestThrottleRT", sskRequestThrottleRT.exportFieldSet()); - fs.put("CHKInsertThrottleRT", chkInsertThrottleRT.exportFieldSet()); - fs.put("SSKInsertThrottleRT", sskInsertThrottleRT.exportFieldSet()); return fs; } - - public double getWindow(boolean realTime) { - return getThrottleWindow(realTime).currentValue(realTime); - } - - public double getRTT(boolean isSSK, boolean isInsert, boolean realTime) { - return getThrottle(isSSK, isInsert, realTime).getRTT(); - } - - public double getDelay(boolean isSSK, boolean isInsert, boolean realTime) { - return getThrottle(isSSK, isInsert, realTime).getDelay(); - } - - MyRequestThrottle getThrottle(boolean isSSK, boolean isInsert, boolean realTime) { - if(realTime) { - if(isSSK) { - if(isInsert) return sskInsertThrottleRT; - else return sskRequestThrottleRT; - } else { - if(isInsert) return chkInsertThrottleRT; - else return chkRequestThrottleRT; - } - } else { - if(isSSK) { - if(isInsert) return sskInsertThrottleBulk; - else return sskRequestThrottleBulk; - } else { - if(isInsert) return chkInsertThrottleBulk; - else return chkRequestThrottleBulk; - } - } - } public String statsPageLine(boolean isSSK, boolean isInsert, boolean realTime) { + MyStats stats = getStats(isSSK, isInsert, realTime); + StringBuilder sb = new StringBuilder(100); sb.append(isSSK ? "SSK" : "CHK"); sb.append(' '); sb.append(isInsert ? "Insert" : "Request"); sb.append(' '); sb.append(realTime ? "RealTime" : "Bulk"); - sb.append(" RTT="); - MyRequestThrottle throttle = getThrottle(isSSK, isInsert, realTime); - sb.append(TimeUtil.formatTime((long)throttle.getRTT(), 2, true)); - sb.append(" delay="); - sb.append(TimeUtil.formatTime(throttle.getDelay(), 2, true)); - sb.append(" bw="); - sb.append(throttle.getRate()); - sb.append("B/sec"); + sb.append(" AvgCompletionTime="); + sb.append(TimeUtil.formatTime(stats.getRTT(), 2, true)); + sb.append(" DroppedRejectedOverload=" + + (stats.getDroppedRatio() * 100.0f) + "% (" + + stats.getDropped() + "/" + stats.getTotal() + ")"); return sb.toString(); } - public String diagnosticThrottlesLine(boolean mode) { - StringBuilder sb = new StringBuilder(); - if(mode) { - sb.append("Request window: "); - sb.append(throttleWindowRequest.toString()); - sb.append(", Insert window: "); - sb.append(throttleWindowInsert.toString()); - } else { - sb.append("CHK window: "); - sb.append(throttleWindowCHK.toString()); - sb.append(", SSK window: "); - sb.append(throttleWindowSSK.toString()); - } - return sb.toString(); - } - - public double getRealWindow(boolean realTime) { - return getThrottleWindow(realTime).realCurrentValue(); - } - public long countQueuedRequests() { return chkFetchSchedulerBulk.countQueuedRequests() + sskFetchSchedulerBulk.countQueuedRequests() + @@ -385,15 +302,15 @@ public ClientRequestScheduler getScheduler(boolean ssk, boolean insert, } } - public void setGlobalSalt(byte[] salt) { - chkFetchSchedulerBulk.startCore(salt); - sskFetchSchedulerBulk.startCore(salt); - chkPutSchedulerBulk.startCore(salt); - sskPutSchedulerBulk.startCore(salt); - chkFetchSchedulerRT.startCore(salt); - sskFetchSchedulerRT.startCore(salt); - chkPutSchedulerRT.startCore(salt); - sskPutSchedulerRT.startCore(salt); - } + public void setGlobalSalt(byte[] salt) { + chkFetchSchedulerBulk.startCore(salt); + sskFetchSchedulerBulk.startCore(salt); + chkPutSchedulerBulk.startCore(salt); + sskPutSchedulerBulk.startCore(salt); + chkFetchSchedulerRT.startCore(salt); + sskFetchSchedulerRT.startCore(salt); + chkPutSchedulerRT.startCore(salt); + sskPutSchedulerRT.startCore(salt); + } } diff --git a/src/freenet/node/ThrottleWindowManager.java b/src/freenet/node/ThrottleWindowManager.java deleted file mode 100644 index 469fc31acea..00000000000 --- a/src/freenet/node/ThrottleWindowManager.java +++ /dev/null @@ -1,83 +0,0 @@ -/* This code is part of Freenet. It is distributed under the GNU General - * Public License, version 2 (or at your option any later version). See - * http://www.gnu.org/ for further details of the GPL. */ -package freenet.node; - -import freenet.support.LogThresholdCallback; -import freenet.support.Logger; -import freenet.support.SimpleFieldSet; -import freenet.support.Logger.LogLevel; - -public class ThrottleWindowManager { - private static volatile boolean logMINOR; - - static { - Logger.registerLogThresholdCallback(new LogThresholdCallback() { - @Override - public void shouldUpdate() { - logMINOR = Logger.shouldLog(LogLevel.MINOR, this); - } - }); - } - - static final float PACKET_DROP_DECREASE_MULTIPLE = 0.97f; - static final float PACKET_TRANSMIT_INCREMENT = (4 * (1 - (PACKET_DROP_DECREASE_MULTIPLE * PACKET_DROP_DECREASE_MULTIPLE))) / 3; - - private long _totalPackets = 0, _droppedPackets = 0; - private double _simulatedWindowSize = 2; - - private final Node node; - - public ThrottleWindowManager(double def, SimpleFieldSet fs, Node node) { - this.node = node; - if(fs != null) { - _totalPackets = fs.getInt("TotalPackets", 0); - _droppedPackets = fs.getInt("DroppedPackets", 0); - _simulatedWindowSize = fs.getDouble("SimulatedWindowSize", def); - } else { - _simulatedWindowSize = def; - } - } - - public synchronized double currentValue(boolean realTime) { - if (_simulatedWindowSize < 1.0) { - _simulatedWindowSize = 1.0F; - } - return _simulatedWindowSize * Math.max(1, node.peers.countNonBackedOffPeers(realTime)); - } - - public synchronized void rejectedOverload() { - _droppedPackets++; - _totalPackets++; - _simulatedWindowSize *= PACKET_DROP_DECREASE_MULTIPLE; - if(logMINOR) - Logger.minor(this, "request rejected overload: "+this); - } - - public synchronized void requestCompleted() { - _totalPackets++; - _simulatedWindowSize += (PACKET_TRANSMIT_INCREMENT / _simulatedWindowSize); - if(logMINOR) - Logger.minor(this, "requestCompleted on "+this); - } - - @Override - public synchronized String toString() { - return super.toString()+" w: " - + _simulatedWindowSize + ", d:" - + (((float) _droppedPackets / (float) _totalPackets)) + '=' +_droppedPackets+ '/' +_totalPackets; - } - - public SimpleFieldSet exportFieldSet(boolean shortLived) { - SimpleFieldSet fs = new SimpleFieldSet(shortLived); - fs.putSingle("Type", "ThrottleWindowManager"); - fs.put("TotalPackets", _totalPackets); - fs.put("DroppedPackets", _droppedPackets); - fs.put("SimulatedWindowSize", _simulatedWindowSize); - return fs; - } - - public double realCurrentValue() { - return _simulatedWindowSize; - } -}