ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/doc/LazyLinks.txt
Revision: 31
Committed: Sun Oct 2 20:34:05 2005 UTC (18 years, 5 months ago) by knight
Content type: text/plain
File size: 9117 byte(s)
Log Message:
- Fix svn:keywords

File Contents

# Content
1 $Id$
2 Lazy Links
3 ==========
4 (Ideas by Dianora and orabidoo; initial spec by orabidoo)
5
6 Basic idea: leaf servers don't really need to know everything about
7 every single user and channel out there; connecting a
8 new leaf server to the network should be fast, easy and
9 cheap, instead of taking ages to exchange information
10 about the state of the whole network.
11
12 The result is that we move, from a loop-less graph
13 topology, to a kind of starfish one, where hubs
14 form a core (interconnected by the traditional IRC
15 protocol), and leaves are just appendages on hubs.
16
17
18 In the rest of this text, we assume that the local network configuration
19 looks like this:
20
21
22 LLL <---> HUB <---> OH <---> ....
23 ^
24 |
25 v
26 ALL
27
28 where LLL and ALL are Lazy Link Leaves, Hub is a Hub, and OH is another
29 hub.
30
31
32 1) Channels
33
34 Hubs, as usual, have full information about all channels, with their
35 membership, chanop status, TS, etc. This information is authoritative,
36 which means that they can use it to make decisions such as "should this
37 user be given ops at this point". This is just the way things are now
38 already. And, as usual, traditional leaves have all this information
39 too, and keep having it.
40
41 Lazy Leaves, OTOH, depend on their uplinks for much of their
42 information. They have partial information, meaning that they don't
43 have the full channel list. However, when they have something about a
44 channel, they do have *everything* about it, and their information is
45 authoritative, so they can decide locally on chanop matters.
46
47 For this, hubs need to know which channels each of its Lazy Leaves has.
48 This is necessarily a double-ended map; it can't be just a single flag
49 on each channel. For efficiency, it could be implemented on the hub by
50 adding a 32-bit int to the server-link structure, and assigning a
51 bitmask (one of 1, 2, 4, ... up to 0x80000000) to each of its Lazy Leaf
52 links. That would support up to 32 Lazy Leaves per hub, and make it
53 really easy and cheap to keep this information. (The only slight
54 downside being that, when a Lazy Leaf link breaks, you need to clear a
55 bit on every single channel.)
56
57
58 1.1) Joining
59
60 When a client on a LLL sends a "JOIN #channel", LLL does as usual: if it
61 has the channel locally, it just joins the user, sends an SJOIN to HUB,
62 and all is well; if it doesn't have the channel, it creates it, sends a
63 SJOIN to HUB with the current time as the TS. LLL tells the user that it
64 has joined the channel, but it doesn't tell it that it has ops yet. So
65 LLL sends
66
67 [LLL -> HUB] :LLL SJOIN LLL_TS #channel :@LLLuser
68 [LLL -> LLLuser] :LLLuser JOIN #channel
69
70 When HUB gets a SJOIN from LLL, it needs to do a lot of the deciding that
71 normally goes into m_join:
72
73 @) if LLL's bit is already set for #channel, then this is not the
74 first time LLL is dealing with #channel, so just process it as
75 a normal SJOIN.
76
77 otherwise:
78
79 a) if myuser cannot join by can_join rules, send a KICK to LLL:
80 [HUB --> LLL] :HUB KICK #channel LLLuser :sorry, the channel was +i
81
82 in this case, LLL's bit doesn't get set for #channel on HUB.
83
84 b) if myuser's join is OK and must be given ops (by usual TS
85 rules, meaning that either LLL_TS < HUB_TS, or the channel
86 is opless or didn't exist on the hub side), then HUB sends
87 something back that validates the join:
88 [HUB -> LLL] :HUB SJOIN OLDER_TS #channel +modes :@LLLuser +other users
89
90 c) if myuser's join is OK but must not be given ops, the HUB
91 sends the same kind of thing back, but without marking ops:
92 [HUB --> LLL] :HUB SJOIN OLDER_TS #channel +modes :LLLuser @other +users
93
94 in this case, as in case b), HUB sets LLL's bit for #channel,
95 so it knows that that LLL knows about that channel now.
96
97 When LLL gets a SJOIN from its hub that includes in the userlist one of
98 LLL's local users, it interprets that that validates a join. If LLLuser
99 has ops in that list, then LLL sends:
100
101 [LLL --> LLLuser] :HUB MODE #channel +o LLLuser
102
103 If not, it just skips that nick from the list. In either case, it
104 processes the rest of the SJOIN information (modes, other nicks) by the
105 usual SJOIN rules.
106
107
108 1.2) Bursts
109
110 The beauty of this is that, with the rules above, channel bursts get
111 avoided, without the need to do anything more.
112
113 When LLL and HUB connect to each other, LLL sends a channel burst as
114 usual; HUB doesn't. By the rules above, HUB will reply to each first
115 LLL's SJOIN for a channel with a SJOIN back with its own info. So at the
116 end of the burst, LLL has been put up to date with all the channels it
117 needs to know about.
118
119
120 1.3) Parts, Kicks and Modes
121
122 When one of LLL's clients (say, LLLuser) leaves a channel, or is kicked
123 out of it, LLL needs to check if that was the last of its clients for
124 that channel.
125
126 If that is the case, then LLL needs to inform HUB that it no longer holds
127 #channel, and destroy its local information about #channel:
128
129 [LLL -> HUB] :LLL DROP #channel
130
131 Upon receiving a "DROP" command from a Lazy Leaf, the Hub just clears
132 the Lazy Leaf's bit on that channel.
133
134 Alternatively, a Lazy Leaf could decide to cache channels even without
135 having any clients on them. All it has to do is not send the "DROP"
136 command to its hub.
137
138 For MODE commands coming from the rest of the net and related to
139 #channel, HUB only needs to pass them to LLL if LLL's bit is set for
140 #channel.
141
142 For MODE changes related to #channel and done by local users on LLL,
143 LLL just passes them as usual to HUB.
144
145 For the special "MODE #channel" query, done on LLL, for a channel that
146 doesn't exist on LLL, this must be routed through HUB:
147
148 [LLL --> HUB] :LLLuser MODE #channel
149 [HUB --> LLL] :HUB (numeric) #channel modes
150
151
152 2) Nicks
153
154 Nicks are simpler, because they are atomic, there is no list associated
155 with them.
156
157 Again, the hub needs to know, for each nick, which of its Lazy Leaves
158 know of it. This can be done with the same 32-bit bitmask as with
159 servers. For each user, the associated bit is 1, unless a NICK command
160 has been sent or received for that user, on the given Lazy Leaf link.
161
162 Once again too, the connect burst gets reduced to just the smaller side:
163 the Lazy Leaf dumps its user base on the hub, but not the other way
164 round.
165
166 When a Lazy Leaf gets a request from one of its local clients, that
167 relates to a nick LLL doesn't have, this must be routed through HUB.
168
169
170 2.1) WHOIS
171
172 For simplicity, we could kill multiple-destination WHOIS, if that's not
173 already done, and all kinds of WHOIS *pattern*.
174
175 When LLLuser does "WHOIS somenick", if the nick is known to LLL, it
176 replies normally. If it isn't, then LLL routes it to HUB:
177
178 [LLL --> HUB] :LLLuser WHOIS Somenick
179
180 HUB replies with the usual numeric, and also with a burst-style NICK
181 introduction, so that from that point on LLL knows about Somenick. HUB
182 also sets LLL's bit for Somenick.
183
184 [HUB --> LLL] :HUB (numerics) WHOIS info
185 [HUB --> LLL] NICK nickTS Somenick HopCount Umode ......
186
187
188 2.2) NOTIFY and USERHOST
189
190 These all take lists of users; for a NOTIFY or USERHOST on LLL from one
191 of its users, the server checks if *all* of the nicks involved are
192 known. If at least one isn't, then the request must be passed as such
193 to HUB. HUB then replies to the client, and also sends a NICK
194 introduction for each client that LLL didn't previously have.
195
196 Note: this kind of sucks, because most NOTIFY lines will tend to include
197 a nick or two that isn't on IRC at the moment, which means they will be
198 relayed. With almost every client out there having NOTIFY, this might
199 well nullify the whole advantage of nick laziness. Or maybe not.
200 Someone needs to do some math on it, or some testing, or both.
201
202
203 2.3) PRIVMSG and NOTICE
204
205 When LLLuser sends "PRIVMSG somenick :message", this must be sent to
206 HUB, even if somenick isn't known locally. HUB will figure it out,
207 and possibly send a numeric back.
208
209 Same for NOTICE.
210
211
212 2.4) Anything else???
213
214 We've missed a bunch here... NAMES, WHO, TRACE, and probably others I
215 can't think of.
216
217 NAMES actually belongs to channels, and might as well not get routed
218 (just don't reply) if a LLLUser tries a NAMES for a #channel that it
219 isn't on, and that LLL doesn't have any info on.
220
221 for WHO, if there's a pattern, just pass the entire command to HUB and
222 let it reply to LLLUser through the link (without introducing any extra
223 NICKs here).
224
225 for TRACE, if the nick is locally unknown, just pass the thing to HUB
226 and let it deal with it.
227
228
229 4) Avoiding Desyncs
230
231 There is one particularly treacherous potential desync: a Lazy Leaf is
232 convinced that it has authoritative information about a channel, but its
233 hub is convinced that the leaf doesn't. The hub doesn't keep sending
234 new information, so the leaf's info grows stale, but it keeps acting on
235 it, which eventually leads to wrong decisions.
236
237 It is important that the protocol ensures that such desyncs are
238 impossible. There should also be periodic cleanup, whereby a Lazy Leaf
239 scans its own channel-user list, and deletes its own information about
240 any channel on which it doesn't have any local users (and complains to
241 its opers about it, because that should never happen).

Properties

Name Value
svn:eol-style native
svn:keywords "Id Revision"