Geek++ · Dossier 09 / 25

A4AF, NNP, états d’une source et changement de fichier

Étude technique publique · 4,206 mots · ≈ 19 min de lecture attentive

Étude intégraleSans réflexion CODEXSources & constantes conservées
A4AF / NNP
SOURCE
Fichier A
demandé
Fichier B
A4AF
Fichier C
NNP

0. Résumé exécutif

Ce dossier ferme plusieurs questions ouvertes par D06, D07 et D08.

Le moteur A4AF de la branche Community 0.72a est déjà sophistiqué :

un CUpDownClient
→ un m_reqfile actif
→ plusieurs fichiers alternatifs

m_OtherRequests_list
m_OtherNoNeeded_list

chaque CPartFile
→ srclist active
→ A4AFsrclist

Le swap prend en compte :

priorités catégories/fichiers
source limits
reask timers
NNP
Source Exchange
Remote Queue Rank
suspensions de swap

La découverte la plus importante est toutefois sémantique :

DS_NONEEDEDPARTS peut représenter plus d’une cause.

Dans SendBlockRequests(), si CreateBlockRequests() ne parvient à produire aucun nouveau bloc, le client est immédiatement :

SendCancelTransfer()
SetDownloadState(DS_NONEEDEDPARTS)
SwapToAnotherFile(...)

Or l’absence de bloc nouveau ne prouve pas nécessairement :

le pair ne possède aucune partie dont nous avons besoin

Elle peut aussi signifier :

le pair possède des parties utiles
mais tous les gaps correspondants sont déjà réservés

Cette différence est particulièrement importante avec Endgame by Akshaan E6bis.

Deuxième découverte importante :

FILEREASKTIME = 29 min
NNP reask = 58 min

et SwapToRightFile() introduit en plus une rotation NNP :

58 min × nombre de fichiers NNP associés au client

afin d’espacer les reasks entre plusieurs NNP.

Sur un client associé à de nombreux fichiers, une association NNP peut donc rester longtemps sans être revisitée.

C’est raisonnable si le pair distant n’a rien changé.

Mais D07 a montré que notre propre gap list peut changer localement après :

corruption
AICH Recovery
ICH
Endgame reservation release

Une source NNP peut donc redevenir utile sans aucun changement de Part Status distant.

Event-Driven A4AF Reclassification

Principe :

événement local qui change les gaps
→ reclassifier localement les A4AF/NNP
→ aucun paquet réseau nécessaire
→ les timers réseau restent respectés
→ Tail Source Wakeup reçoit immédiatement
   une vue correcte des sources potentiellement utiles

Le vieux Delayed NNP NetF reste pertinent comme protection supplémentaire pour une source actuellement en téléchargement juste avant son passage NNP.

Mais il ne devrait probablement pas être porté sous forme d’un simple timer global fixe de 30 s.


1. A4AF : modèle de données réel

1.1 Fichier actif

Chaque CUpDownClient possède :

m_reqfile

Le client appartient alors à :

m_reqfile->srclist

1.2 Fichiers alternatifs

Le même client conserve :

m_OtherRequests_list
m_OtherNoNeeded_list

et chacun de ces fichiers conserve le client dans :

CPartFile::A4AFsrclist

Il existe donc une relation bidirectionnelle.


2. AddRequestForAnotherFile()

Dans 0.72a :

if (m_OtherNoNeeded_list.Find(file)
    || m_OtherRequests_list.Find(file))
    return false;

m_OtherRequests_list.AddTail(file);
file->A4AFsrclist.AddTail(this);

Sens

Une source découverte pour un fichier alors qu’elle est déjà utilisée ailleurs :

n’est pas clonée

Elle devient une source A4AF de l’autre fichier.

C’est exactement ce que D08 observait lors du dédoublonnage inter-fichiers.


3. Deux classes A4AF

m_OtherRequests_list

Association connue et potentiellement utilisable.

m_OtherNoNeeded_list

Association pour laquelle le client a précédemment été classé :

NNP

Cela permet des reask plus espacés et une sélection différente dans SwapToRightFile().


4. DoSwap() : ce que signifie réellement un swap

Séquence :

ancien m_reqfile
    ↓
retiré de srclist

nouveau fichier
    ↓
retiré de son A4AFsrclist

ancien fichier
    ↓
ajouté dans A4AFsrclist
    ↓
OtherRequests ou OtherNoNeeded

client
    ↓
SetDownloadState(DS_NONE)
SetRequestFile(nouveau)

nouveau fichier
    ↓
client ajouté dans srclist

Le client réseau reste le même.


5. Classification de l’ancien fichier pendant le swap

Dans DoSwap() :

if (GetDownloadState() == DS_NONEEDEDPARTS)
    m_OtherNoNeeded_list.AddTail(m_reqfile);
else
    m_OtherRequests_list.AddTail(m_reqfile);

Conséquence

L’état du client au moment du swap détermine durablement quelle liste A4AF recevra l’ancien fichier.

C’est une raison supplémentaire pour ne pas classifier NNP trop tôt en Endgame.


6. État NNP : origine par Part Status

ProcessFileStatus() compare la carte distante avec nos besoins locaux.

Si aucun besoin n’est visible en TCP :

SetDownloadState(DS_NONEEDEDPARTS);
SwapToAnotherFile(...);

Donc :

NNP → A4AF swap immédiat

dans ce chemin.

UDP

Le même traitement UDP peut définir :

DS_NONEEDEDPARTS

mais l’appel SwapToAnotherFile() correspondant est commenté dans la branche étudiée.

Ce n’est donc pas parfaitement symétrique.


7. État NNP : origine par scheduler de blocs

Dans SendBlockRequests() :

CreateBlockRequests(blockCount);

if (m_PendingBlocks_list.IsEmpty()) {
    SendCancelTransfer();
    SetDownloadState(DS_NONEEDEDPARTS);
    SwapToAnotherFile(...);
    return;
}

C’est le point le plus important du dossier.

Cette branche ne demande pas :

« la Part Status du pair
a-t-elle zéro intersection avec nos gaps ? »

Elle constate seulement :

« aucun nouveau bloc n'a été placé
dans la pending list »

8. NNP sémantiquement ambigu

Il faut donc distinguer au moins :

NNP-1 — réellement aucune partie utile

remote available parts
∩
local gaps
=
vide

NNP-2 — parties utiles mais travail déjà réservé

remote available parts
∩
local gaps
!=
vide

mais

toutes les plages pertinentes
sont déjà requested/reserved

Dans eMule historique, les deux peuvent converger vers :

DS_NONEEDEDPARTS

10. Baseline E6bis

D06 établit :

Endgame by Akshaan E6bis = baseline

et documente déjà :

Locked Block Recovery
Speculative Block Racing
Partial Final-Tail Rescue
Stale Pipeline Bypass
Tail Source Wakeup
SOURCE_LIMITED

D09 ne doit pas créer un second scheduler concurrent.

Il doit fournir à E6bis une classification correcte du cycle de vie des sources.


11. SetDownloadState(DS_NONEEDEDPARTS) modifie aussi le timer

Le code contient explicitement :

case DS_NONEEDEDPARTS:
    SetLastAskedTime();

Commentaire :

TCP asks never set re-ask time
if the result is NNP

Donc le passage NNP n’est pas seulement visuel.

Il modifie la prochaine fenêtre de reask.


12. Timers de base

Opcodes.h 0.72a :

FILEREASKTIME      = 29 min
MIN_REQUESTTIME    = 10 min
PURGESOURCESWAPSTOP = 15 min

GetTimeUntilReask() applique :

normal       → 29 min
NNP          → 58 min
short/aggr.  → 10 min

Les 58 min sont :

FILEREASKTIME × 2

13. Pourquoi le 29 min historique existe

Ce timer protège le réseau contre les requêtes répétées.

D09 ne propose pas de réduire globalement :

29 min

ni :

58 min

Le problème identifié n’est pas :

« les timers sont trop longs »

mais :

« un événement local peut rendre une source utile
sans nécessiter un nouveau reask réseau »

14. Rotation de plusieurs NNP : détail remarquable

Dans SwapToRightFile() :

allNnpReaskTime =
    FILEREASKTIME * 2 *
    (m_OtherNoNeeded_list.GetCount()
     + (current == NNP ? 1 : 0));

Avec :

FILEREASKTIME = 29 min

cela donne :

1 NNP → 58 min
2 NNP → 116 min
3 NNP → 174 min
5 NNP → 290 min
10 NNP → 580 min

Important

Ce n’est pas un délai global de connexion.

C’est une logique de rotation/revisite des associations NNP d’un même client.

Elle cherche à répartir les reasks entre plusieurs fichiers NNP.


15. Intention historique

Commentaire du source :

wait two re-ask interval for each nnp file
before re-asking an nnp file

L’intention est raisonnable :

ne pas reposer la même question
à la même source
pour dix fichiers
toutes les 58 minutes simultanément

Cela répartit l’overhead.


17. D07 donne la pièce manquante

AICH peut transformer :

partie complète

en :

une ou plusieurs gaps de 180 KiB

ou ICH peut rouvrir la partie.

À cet instant :

les besoins locaux changent immédiatement

mais les Part Status distantes déjà connues restent potentiellement exploitables.

Conclusion D07 → D09

Après :

PART_CORRUPT
AICH_RECOVERY
GAP_REOPENED

il faut envisager une réévaluation locale A4AF/NNP.


18. Réévaluer localement ≠ reask réseau

C’est le cœur de la proposition.

Nous possédons déjà souvent :

source->PartStatus

Donc après AddGap() :

for each A4AF/NNP source:
    cached remote PartStatus
        ∩
    new local gap map

peut être recalculé sans paquet.


19. Nouveau statut conceptuel

Nom de travail :

A4AF_RECLASSIFY_LOCAL

ou :

SourceNeedReevaluation

Événement :

Gap topology changed

Causes :

corruption
AICH
ICH
Endgame block release
file completion of a part
possibly manual priority/state change

20. Ce qui peut être recalculé immédiatement

Sans réseau :

source owns newly-needed part?
source belongs to this file?
source currently A4AF?
source in OtherNoNeeded?
file priority
current source count
Endgame SOURCE_LIMITED

Ce qui ne peut pas être garanti :

source still online
source still owns the part now
remote queue state
fresh QR
fresh Part Status

Dossier 05 :

cached PartStatus remains REMOTE_CLAIM

mais c’est déjà la même base que le scheduler historique utilisait.


21. Classification proposée des causes NNP

NNP_NO_PART_OVERLAP

Aucune partie annoncée du pair ne croise les gaps actuelles.

NNP_ALL_WORK_RESERVED

La source possède des parties utiles, mais toutes les plages pertinentes sont déjà réservées.

NNP_ENDGAME_TRANSIENT

Cas précédent dans un fichier E6bis actif avec forte probabilité de libération/racing/reallocation.

NNP_POST_INTEGRITY_CHANGE

Gap récemment rouverte par MD4/AICH/ICH.

NNP_STATUS_UNKNOWN

Part Status absente ou non exploitable.

NNP_STABLE

Classification stable après revalidation locale.


22. Pourquoi cette classification est préférable à « Delayed NNP partout »

Un délai uniforme de 30 s ferait aussi attendre :

une source réellement inutile

alors qu’elle pourrait immédiatement servir un autre fichier A4AF.

Cela peut réduire le débit total.

23. NetF Delayed NNP

Le rapport historique NetF établit :

grâce ≈ 30 s
reask Part Status
puis seulement :
CancelTransfer
DS_NONEEDEDPARTS
SwapToAnotherFile

Le descriptif NetF explique explicitement l’objectif :

keeps downloading sources a little bit longer
in case a part turns out corrupt

Ce mécanisme répond donc bien à un vrai problème.


24. Pourquoi ne pas copier les 30 secondes

Trois raisons.

1. Matériel/réseau

30 s vient d’un contexte ancien.

2. E6bis

Nous savons déjà mesurer :

rate collapse
tail risk
remaining work
owners
source limited

3. Local gap events

Après corruption, nous n’avons pas forcément besoin d’attendre une nouvelle Part Status.

Nous pouvons souvent savoir immédiatement que la source redevient potentiellement utile.


25. Delayed NNP adaptatif éventuel

Si un délai de grâce reste nécessaire pour une source actuellement en téléchargement :

grace = bornée

et dérivée de facteurs comme :

RTT
débit actuel
temps depuis dernier payload
Endgame state
probabilité de gap liberation
A4AF alternative disponible

Pas besoin de fixer maintenant une formule.

Première phase :

shadow telemetry

26. Xtreme Just In Time Swapping

Changelog Xtreme 4.2 beta 1 :

when you are downloading from a client
and this client doesn't have anymore chunks for you,
the download is continued with an A4AF

La branche 0.72a étudiée possède aujourd’hui :

SendBlockRequests()
→ no pending block
→ Cancel
→ NNP
→ SwapToAnotherFile

Conclusion historique prudente

Le même problème et le même comportement général apparaissent dans Xtreme puis dans la branche moderne.

Nous n’avons pas ici la preuve documentaire suffisante pour attribuer directement l’implémentation 0.72a à Xtreme.


27. Pourquoi Just-In-Time Swapping est encore une bonne idée

Hors Endgame :

source A n'a plus rien pour Fichier X
mais possède Fichier Y

slot distant déjà obtenu

Réutiliser immédiatement ce slot pour Y peut éviter :

perdre une occasion de transfert

Le problème n’est donc pas le swap lui-même.

Le problème est de savoir si le diagnostic :

« plus rien pour X »

est réellement stable.


28. Auto-A4AF

Le changelog Xtreme indique aussi :

Auto-A4AF-check

et le corpus Mods souligne l’importance historique de la gestion A4AF dans Xtreme/Sivka/ZZUL.

Ces références sont utiles pour la suite.

Mais sans les sources exactes de chaque version, D09 ne transforme pas les noms de features en algorithmes supposés.

Règle corpus

changelog = preuve d’existence/intention
source = preuve de comportement détaillé

30. Sources limits dans SwapToRightFile()

Le swap essaie de ne pas déplacer la source vers un fichier déjà saturé.

Il traite aussi plus sévèrement les NNP autour d’environ :

80 % de MaxSources

dans certaines branches.

Sens

A4AF est également un mécanisme de répartition des sources entre fichiers.


31. Source Exchange et A4AF

La logique compare aussi :

IsSourceRequestAllowed(file)
AllowSwapForSourceExchange()

et peut conserver/déplacer la source afin d’obtenir une opportunité SX.

Protection :

30 s

sur lastSwapForSourceExchangeTick.

D08 recommande de conserver cette hystérésis.


32. Remote QR dans A4AF

SwapToRightFile() contient :

DS_ONQUEUE && RemoteQueueRank <= 50

et l’inverse :

RemoteQueueRank > 50

dans les décisions liées à SX.

D05 a établi :

Remote QR = REMOTE_CLAIM

D09

Ajouter aux traces :

remote_qr_influenced_swap=yes/no

sans modifier immédiatement le comportement.


33. DS_REMOTEQUEUEFULL : fossile intéressant

ClientStateDefs.h de la 0.72a contient :

DS_REMOTEQUEUEFULL
// not used yet, except in statistics

Pourtant SwapToAnotherFile() et SwapToRightFile() contiennent encore des branches qui le testent.

Hypothèse

Il s’agit probablement :

d’une branche historique / défensive
ou d’un état devenu pratiquement mort

34. Le vrai état Queue Full moderne

La branche possède en parallèle un booléen/état :

RemoteQueueFull

distinct de EDownloadState.

Au début d’un FileRequest vers un eMule :

SetRemoteQueueFull(true)
SetRemoteQueueRank(0)

jusqu’à réception d’une information de queue.

Les deux concepts ne doivent donc pas être confondus :

DS_REMOTEQUEUEFULL
vs
m_bRemoteQueueFull / IsRemoteQueueFull()

35. A4AF Save CPU

La branche possède :

A4AFSaveCpu

défaut :

false

Lorsque activé, SwapToAnotherFile() peut renoncer très tôt à certaines évaluations si le client peut rester sur le fichier courant.

Historique

Cette option témoigne d’une époque où scanner fréquemment les associations A4AF pouvait être considéré coûteux.

36. DontSwapTo() et suspension

DontSwapTo(file) enregistre un timestamp.

IsSwapSuspended() bloque alors un retour sur ce fichier pendant :

PURGESOURCESWAPSTOP = 15 min

sauf expiration.

Exemples d’usage retrouvés :

File Not Found
AICH mismatch

Important

Dans SetDownloadState(DS_NONEEDEDPARTS) :

//DontSwapTo(m_reqfile);

est commenté.

Un simple NNP ne déclenche donc pas ce verrouillage par cette voie.


37. Pourquoi c’est logique

NNP peut être temporaire.

Interdire pendant 15 min tout retour au fichier après chaque NNP aurait pu empêcher des réaffectations utiles.

Les reask timers suffisent déjà largement à limiter l’agitation.


38. FNF ≠ NNP

UDPReaskFNF() :

source dit :
« je n'ai pas ce fichier »

→ DontSwapTo(m_reqfile) → tentative d’autre fichier → sinon suppression source

C’est beaucoup plus fort que :

« je possède le fichier
mais rien dont tu as besoin maintenant »

Trust semantics

FNF
≠
NNP

39. AICH mismatch ≠ simple NNP

Si le FileIdentifier/AICH ne correspond pas :

DontSwapTo(file)
→ tentative A4AF
→ sinon suppression

C’est encore une autre raison de changement de fichier.

40. Le booléen reason actuel n’est pas structuré

SwapToAnotherFile() reçoit une chaîne :

"A4AF for NNP file..."
"Source says it doesn't have the file..."
...

utile au log.

Mais pour l’analyse automatisée, une chaîne n’est pas idéale.

41. Enum proposé

PeriodicReask
NNPPartStatus
NNPNoRequestableBlock
FileNotFound
AICHMismatch
SourceExchangeOpportunity
FileCompleted
ManualSwap
EndgameTailWakeup
IntegrityGapReopened
Unknown

V1 :

observation seulement

42. A4AF Decision Trace

Format proposé :

[A4AF_DECISION]

client=session:42

from=file:A
to=file:B

reason=NNP_NO_REQUESTABLE_BLOCK

from_state=DOWNLOADING
to_is_nnp=no

priority_from=normal
priority_to=high

sources_from=38
sources_to=5

remote_qr=27
remote_qr_trust=UNVERIFIED

sx_from_allowed=no
sx_to_allowed=yes

endgame=ACTIVE
source_limited=yes

decision=SWAP

43. Pourquoi la raison NNP doit être déterminée avant SetDownloadState

Aujourd’hui, dans le chemin :

CreateBlockRequests()
→ Pending empty
→ NNP

l’information :

« pourquoi aucun bloc ? »

est perdue.

44. Lien avec Dynamic Request Size D06

Si Dynamic Request Size est un jour testé :

moins de grandes réservations
→ moins de ALL_USEFUL_GAPS_RESERVED
→ moins de faux/transitoires NNP

D09 fournit donc une métrique indirecte pour juger ce candidat.


45. Lien avec Stale Pipeline Bypass

E6 avait justement trouvé :

anciennes réservations gagnées
→ encore présentes
→ fausse impression que tout est occupé

Stale Pipeline Bypass corrige ce type de situation.

D09

Compteur intéressant :

NNP_NO_REQUESTABLE_BLOCK
avant/après stale-pipeline filtering

Cela peut confirmer que le problème est déjà largement résolu par E6bis.


46. Lien avec Speculative Racing

Si :

source rapide possède le dernier bloc
mais bloc déjà réservé

ancien eMule peut atteindre :

no requestable block

E6bis peut au contraire :

challenger/race

avant de déclarer la source NNP.

Invariant

E6bis opportunity
doit être évaluée
avant A4AF NNP fallback

47. Lien avec Partial Final-Tail Rescue

Même logique.

Si une partie d’un bloc reste gap :

la source peut être utile
sur cette sous-plage

avant que le client soit classé NNP.

Audit

Vérifier l’ordre d’appel réel :

gap discovery
→ E6bis rescue
→ pending construction
→ NNP fallback

48. Lien avec corruption

D07 :

AICH Recovery
→ FillGap bons blocs
→ mauvaises zones restent gaps

ou un hash failure peut :

AddGap()

Question D09

Après cette mutation :

les sources dans m_OtherNoNeeded_list
sont-elles reclassées immédiatement ?

Dans le code officiel inspecté :

UpdatePartsInfo()

recalcule les fréquences depuis srclist.

Il ne constitue pas, à lui seul, un moteur général visible de migration :

OtherNoNeeded → OtherRequests

sur changement local de gaps.

Statut


49. Event-Driven A4AF Reclassification

Nom proposé :

A4AF Need Reclassifier

Entrées :

FileGapChanged
PartCorrupted
AICHRecoveryFinished
EndgameReservationReleased
EndgameSourceLimitedEntered

Sortie :

liste de sources A4AF devenues potentiellement utiles

50. Première version : shadow

Ne déplacer aucune source.

Pour chaque événement :

scan A4AFsrclist
scan source PartStatus
compare new gaps

Log :

[A4AF_RECLASS_SHADOW]

event=AICH_GAP_REOPENED
file=anon:A
a4af_sources=37
previous_nnp=19
now_locally_useful=4

best_candidate=session:72
connected=yes
current_file=B
current_file_priority=normal
target_priority=high

51. Coût CPU

Le scan peut être évité sur :

tous les fichiers

et limité au fichier dont la gap map change.

Complexité approximative :

A4AF sources du fichier
×
part intersection

Sur un PC moderne, probablement faible.

Mais mesurer avant de supprimer A4AFSaveCpu.


52. Optimisation possible par part touchée

Après AICH :

part 42 a changé

Il est inutile de rescanner toutes les parties.

On peut rechercher uniquement :

source->IsPartAvailable(42)

pour chaque A4AF source.

Encore plus léger.


53. Après un Endgame reservation release

Le besoin n’est pas une nouvelle partie.

C’est une nouvelle plage libre dans une partie déjà manquante.

Si la source possède cette partie :

candidate useful

E6bis peut alors utiliser son propre scheduler pour déterminer la plage précise.


54. Ne pas convertir immédiatement la liste

Une source dans OtherNoNeeded peut devenir localement utile, mais :

elle peut être occupée ailleurs
être sous reask timer
ne plus être connectée
avoir une PartStatus ancienne

V1 doit simplement poser un marqueur :

locally_useful_again=true

55. Promotion possible à terme

Après validation :

OtherNoNeeded
→ candidate for OtherRequests / swap

mais seulement à travers les mêmes règles :

priorité
timers
source limit
A4AF
Endgame policy

Ne pas modifier directement les listes depuis l’événement d’intégrité sans passer par le scheduler.


58. Ce que la shadow telemetry doit mesurer

si nous avions attendu :
la source serait-elle redevenue utile ?

combien de temps ?
combien d'octets aurait-elle pu servir ?

pendant ce temps :
un A4AF réel aurait-il transféré sur un autre fichier ?

Cette dernière métrique est essentielle.

Delayed NNP a un coût d’opportunité.


59. Métrique NetF historique

Le rapport Endgame proposait déjà :

NNPGraceRecovered

D09 l’étend :

NNP_GRACE_REUSED
NNP_GRACE_WASTED_TIME
NNP_GRACE_A4AF_OPPORTUNITY_COST

60. Pas de délai fixe sans résultats

30 secondes est une excellente valeur historique de comparaison.

Comparaisons shadow possibles :

5 s
10 s
15 s
30 s
adaptatif

sans réellement retenir la source.


61. Reask Part Status pendant la grâce

NetF redemandait la Part Status.

Local need changed

Exemple corruption locale :

PartStatus distante encore suffisante

Pas forcément besoin de reask.

Remote availability suspected changed

Exemple source vient de finir une partie :

reask peut être utile

mais seulement si les timers/protocole le permettent.


62. Éviter un nouveau flood

chaque NNP
→ PartStatus reask immédiat

La philosophie D01/D08 reste :

réduire les requêtes inutiles

La reclassification locale est justement intéressante parce qu’elle coûte :

0 paquet

63. A4AF et Remote Queue Rank

D05 a démontré que le QR distant est falsifiable.

D09 confirme qu’il influence effectivement :

SwapToRightFile()

Première évolution sûre

Trace :

QR condition changed outcome?
yes/no

Puis simulation :

decision without Remote QR

sans changer le comportement réel.


64. Question à mesurer

Combien de swaps seraient différents si :

Remote QR

était retiré de l’heuristique ?

Si :

presque aucun

le code historique peut être simplifié.

Si :

beaucoup

il faudra étudier une alternative basée sur des observations locales.


65. Possible remplacement à long terme

Pas une recommandation immédiate.

Facteurs vérifiables :

temps depuis dernier transfert
source count réel
file priority
source useful parts
connection success
local queue wait estimate impossible à connaître

Il n’existe pas de substitut parfait au QR parce que le QR apporte précisément une information sur la file distante.

Il faut donc mesurer la valeur de cette information avant de la supprimer.


66. A4AF et SX Provider Quality

D08 proposait :

provider quality
→ tie-break pour choisir à qui demander SX

Cette métrique ne doit pas devenir :

file swap priority générale

Elle ne concerne qu’un rôle :

qualité comme fournisseur de sources

D09 garde les dimensions séparées.


67. A4AF et source quality

Même prudence.

Une source qui transfère bien Fichier A peut être excellente pour A et NNP pour B.

La qualité n’est pas seulement :

client global

mais souvent :

client × fichier × moment

68. Historique Sivka

Le changelog Sivka documente :

A4AF handling v1.2
A4AF counter
R4AF listing
manual swapping all A4AF

Il montre que le sujet était déjà considéré comme complexe assez tôt dans l’histoire des Mods.

Mais D09 ne déduit pas le comportement exact de ces fonctions sans source détaillée correspondante.


69. Historique Xtreme

Le corpus documente :

Auto-A4AF-check
Just in Time Swapping
drop NoNeeded
drop FullQueue
drop HighQR

Cela montre deux philosophies historiques :

réutiliser vite une source

et :

nettoyer les sources jugées peu productives

84. Première implémentation recommandée

D09-V1 — A4AF Decision Trace

Aucun changement de comportement.

Ajouter :

raison
from/to file
list origin
NNP classification shadow
timers
priority
source counts
QR influence
SX influence
E6bis state

85. D09-V2 — NNP Reason Classifier Shadow

Dans le chemin SendBlockRequests() :

avant :

SetDownloadState(DS_NONEEDEDPARTS)

calculer seulement pour log :

NO_PART_OVERLAP
ALL_WORK_RESERVED
ENDGAME_TRANSIENT
UNKNOWN

Aucune modification des décisions.


86. D09-V3 — Gap Event Reclassification Shadow

Sur :

AddGap / corruption
AICH recovery
Endgame reservation release

rechercher les sources dans :

A4AFsrclist

qui redeviennent localement utiles.

Aucun swap.


88. D09-V5 — Adaptive NNP Grace

Seulement si :

des sources actives utiles sont encore perdues
malgré V4 + E6bis

Alors tester une grâce ciblée.

Pas avant.


89. Pourquoi cet ordre est préférable

Il est possible que :

Stale Pipeline Bypass
+
Locked Recovery
+
local reclassification

résolvent presque tous les cas où NetF avait besoin de 30 secondes de délai.

Dans ce cas :

pas besoin d'ajouter une nouvelle attente
mesurer
avant d'empiler des heuristiques

90. Architecture proposée

A4AFManager
    ├── ActiveFile
    ├── OtherRequests
    ├── OtherNoNeeded
    ├── SwapPolicy
    └── ReaskPolicy

NeedClassifier
    ├── NoPartOverlap
    ├── AllWorkReserved
    ├── EndgameTransient
    └── IntegrityReopened

A4AFEventReclassifier
    ├── GapChanged
    ├── Corruption
    ├── AICH
    └── ReservationReleased

A4AFDecisionTrace
    ├── priority
    ├── timers
    ├── SX
    ├── QR
    └── Endgame

Ces noms sont conceptuels.

Le premier port ne doit pas imposer un grand refactor.


91. Invariant de protocole

Tout ce travail reste :

100 % local

Aucun nouveau :

opcode
tag
packet
source exchange version
server feature

n’est nécessaire.


92. Invariant Endgame

Baseline :

E6bis

Toute nouveauté D09 doit démontrer :

meilleur que E6bis

et non simplement :

meilleur que 0.72a officiel

93. Invariant Trust

Ne pas accorder un privilège parce que :

Remote QR dit 4
ModString dit X
client prétend être Complete Source

Les informations distantes restent des assertions.

Les événements locaux :

gap reopened
reservation released
valid bytes received

ont davantage de poids.


94. Invariant réseau

Ne pas transformer la réévaluation locale en :

reask immédiat massif

Le principal intérêt de la proposition est justement :

réagir plus vite
sans augmenter l'overhead

95. Découverte majeure du dossier

D09 permet finalement de reformuler NNP.

Dans l’interface historique :

No Needed Parts

semble décrire uniquement le pair.

En réalité :

NNP est une relation entre la Part Status du pair, notre gap list, l’état des réservations et l’instant où la décision est prise.

C’est beaucoup plus important.


96. Décision actuelle

Pas de port immédiat :

Delayed NNP = 30 s

La priorité est :

D09-V1 Decision Trace
D09-V2 NNP reason shadow
D09-V3 Event-driven reclassification shadow

Si les traces montrent que des sources fraîchement utiles restent dormantes à cause du modèle NNP historique :


97. Gain potentiel attendu

Pas nécessairement un gain sur tous les fichiers.

Principalement :

fichiers rares
corruption proche de la fin
AICH recovery
SOURCE_LIMITED
beaucoup d'A4AF
derniers blocs fortement disputés

Le gain attendu est surtout :

réduire le temps où
une source utile existe déjà
mais reste mal classée localement

98. Ce que nous ne devons pas faire

réduire FILEREASKTIME globalement
supprimer les timers NNP
attendre 30 s sur tous les NNP
forcer tous les A4AF vers le fichier presque fini
bannir les HighQR
utiliser le QR distant comme vérité
réinterroger le réseau après chaque AddGap
dupliquer des CUpDownClient par fichier

99. Relation avec les vieux Mods

NetF WARP

Apporte :

Delayed NNP

et l’explication corruption/endgame.

Xtreme

Apporte historiquement :

Just In Time Swapping
Auto-A4AF

et une forte culture de gestion dynamique des sources.

Sivka

Documente :

A4AF handling
R4AF
compteurs/visibilité

ZZ / ZZUL

La branche officielle étudiée porte explicitement de nombreux marqueurs :

ZZ:DownloadManager

dans l’implémentation A4AF actuelle.

Le moteur moderne est donc déjà le résultat d’années d’évolution communautaire.


100. Conclusion

A4AF n’est pas une petite option d’interface.

C’est un véritable ordonnanceur d’affectation des pairs aux fichiers.

La branche 0.72a sait déjà :

éviter les doublons de clients
mémoriser plusieurs fichiers par source
classer les associations NNP
respecter les priorités
espacer les reasks
tenir compte de SX
réutiliser une source quand elle devient meilleure ailleurs

Mais son modèle NNP reste fondé sur une logique historique où :

« plus de bloc immédiatement demandable »

est très proche de :

« plus rien d'utile chez cette source »

Endgame E6bis, AICH et notre Trust Model rendent cette assimilation moins satisfaisante.

Delayed NNP 30 s partout

mais :

rendre NNP explicable, détecter pourquoi une source est momentanément inutile et réévaluer les associations A4AF lorsqu’un événement local change réellement nos besoins.

C’est une amélioration entièrement locale, compatible avec le réseau existant, directement utile à Tail Source Wakeup et particulièrement pertinente après corruption ou en SOURCE_LIMITED.



Dossier 09 terminé

A4AF, NNP, états d’une source et changement de fichier

← Dossier 08Dossier 10 →