<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pure/link/link.c, branch master</title>
<subtitle>Verified execution runtime unifying state, persistence, and replication.
</subtitle>
<id>http://git.yeowoo.org/pure/atom?h=master</id>
<link rel='self' href='http://git.yeowoo.org/pure/atom?h=master'/>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/'/>
<updated>2026-10-04T09:06:41Z</updated>
<entry>
<title>Let a link's receiver find its streams' inputs again (017, stage 3)</title>
<updated>2026-10-04T09:06:41Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-10-04T09:06:41Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=578d0ab47f22e0185987ed3f8c091129985cec6e'/>
<id>urn:sha1:578d0ab47f22e0185987ed3f8c091129985cec6e</id>
<content type='text'>
A stream finds its input once, when it is made; an app that starts again
with another module may have the input at another number, of another
shape, or none. pure_link_receiver_rebind marks the streams to inputs of
a prefix stale: each finds its input again by name, with the fields it
was laid out with, before its next delivery and at its sender's next
packet, keeping what it holds; one none takes is refused as a new one
would be. pure_link_listener_rebind asks it of the listener's thread.
test-link's rebound case stops its app, starts it with the input at
another number, then of another shape taken by name: all 3,000 records
come once, in order (without the rebind, none after the stop).
</content>
</entry>
<entry>
<title>Take the sending loop out of the links, for the wires to join it (017, 2b)</title>
<updated>2026-10-01T08:00:45Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-10-01T08:00:45Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=50f8ea3c249009fcbe649561e7aba32580bab454'/>
<id>urn:sha1:50f8ea3c249009fcbe649561e7aba32580bab454</id>
<content type='text'>
link/sending.c is the process's sending loop: a sender joins it with its
round and the socket it waits on, and is rounded when its socket is
ready, when pushed, and when its time comes. Links are its first
senders; nothing they do changed. Events of a sender that left while the
loop waited are let go (the epoll is level-triggered: the others' come
again).
</content>
</entry>
<entry>
<title>Push a turn's sends to a link at once, and round only the links that want one (017, 2b-1)</title>
<updated>2026-10-01T07:52:43Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-10-01T07:52:43Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=94e7bb87bce6821e91734f1fcbb6cfd61a008049'/>
<id>urn:sha1:94e7bb87bce6821e91734f1fcbb6cfd61a008049</id>
<content type='text'>
The sending loop was woken by every record queued while it slept: the
owner queues one by one, the loop caught up and slept between them, and
every link took a round on every wake. Four links sent 64k packets of
12 records where threads sent 40k of 20, and ran at 257k sends/s
against 581k. The owner now queues a turn's sends and pushes each link
once; the loop rounds a link only when its socket has answers, it was
pushed, or its time came.
</content>
</entry>
<entry>
<title>Send every link on one loop, not a thread each (017, 2b-1)</title>
<updated>2026-10-01T07:38:47Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-10-01T07:38:47Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=99b221927c6feb595b7758ae9bf8370054028fae'/>
<id>urn:sha1:99b221927c6feb595b7758ae9bf8370054028fae</id>
<content type='text'>
A link sent on a thread of its own, polling its socket and a wake. Now
the process has one sending loop (pure-send), made with the first link
started and stopped with the last closed: an epoll over the links'
sockets and one wake, sleeping until the soonest link's next time. Each
round does for every link what its thread did: answers taken when its
socket had them, its times kept, the receiver looked for again when
probes go unanswered (a new socket joins the epoll), packets sent, and
the owner told of what was stored. A queue wakes the loop only while it
sleeps, once. Events name links by number, so one closed since its
event came is not touched; answers are received into the loop's one
buffer.

A name looked up again (after three probes unanswered) waits where it
is, and every link waits with it; it was so for its own link before.
Every check passes as it did.
</content>
</entry>
<entry>
<title>Take a delivery's fields by name, dropping none</title>
<updated>2026-09-30T04:58:38Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-30T04:58:38Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=5ce7655d613689223050715ff3f8fe5c456ebf11'/>
<id>urn:sha1:5ce7655d613689223050715ff3f8fe5c456ebf11</id>
<content type='text'>
A message from another node was taken only in its input's exact shape
(the link's STREAM shape, fields and order alike; over HTTP, every
field). So a board whose nodes are upgraded one after the other stopped
both ways until both were, and an output and its input whose fields
differ only in order were refused for good (docs/design/014).

An input now takes a message when it has every field the sender sends,
by name, of the same type or one that holds its values (a u32 in a
number, text in bytes); a field only the input has is 0 or empty. One
that sends a field the input lacks is refused: taking it would drop the
value, and with its number heard the value would never come again (two
boards apart for good). So add fields to receivers first and take them
from senders first, and nothing stops or is lost.

The link carries a sender's fields in a new frame, FIELDS (0x0d: names,
shape, u8 count, each {type, name length, name}): after a REFUSED for
another shape the sender puts it in its packets (after OFFER, before
the records, so a receiver that knows no FIELDS reads what it read
before) until the stream is taken, the first time at once. A receiver
seeing another shape waits for the packet's FIELDS before refusing, and
asks its host with them (PureLinkHost.input takes them); REFUSED says 4
when the input lacks a field. Deliveries carry the fields and the host
lays each record out anew (pure_module_takes, pure_module_recast,
pure_module_fields, over pure_send_recast's rule). A stream whose sender
starts again in another shape lets go what it held; the sender sends it
again laid out anew. A refusal already queued for a stream now says the
last reason judged, not the first. Over HTTP a delivery (X-Pure-Source)
may lack fields; an unknown member is still refused.

test-link named: a stream of another shape naming its fields is taken,
200 stored in 47 ms with every delivery naming them; an input that does
not take them refuses (4) and the sender backs off. check.py
server_fields: five outputs, three linked and two over HTTP, fields in
another order taken, an input with a field more taking messages without
it, one lacking a field refusing until it starts again with it, then
taking all. server_upgrade's new receiver declares its fields in another
order. 012 names the frame and the rules.
</content>
</entry>
<entry>
<title>Hold a window of each output's sends in its transport, not the outbox</title>
<updated>2026-09-30T02:32:07Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-30T02:32:07Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=d9e0b6870201d9200b3c225903b43b850475600b'/>
<id>urn:sha1:d9e0b6870201d9200b3c225903b43b850475600b</id>
<content type='text'>
A link's ring and a wire's queue took every saved send of their output
and kept it until delivered: with the receiver down they held the
outbox a second time, 178 B and 313 B more a send (104). Each outlet now
holds a window, --window bytes (4 MiB) and 65,536 sends past what its
receiver has, at least one; the outbox keeps the rest.

The owner remembers each outlet's place in the outbox and looks on from
there after a save and after its transports deliver. Places move back by
the sends that left the outbox since (PureApp.sends_gone), so a trim
before a place skips nothing, and sends queued before are not looked at
again however many wait. pure_app_sent reads a send by its place (the
newest-first visit it replaces is gone); pure_link_held and
pure_wire_held say what a transport holds.

With the receiver down a node now grows by the outbox alone once the
window is full: 219 and 218 B a send over the link and HTTP (399 and
534 B before). check.py server_windows keeps the receivers of a sender's
two outputs, one linked and one over HTTP, down through 300 buys with a
2,000-byte window, then starts them: each applies all 300 once. Without
the refill after deliveries the link stops at 117.
</content>
</entry>
<entry>
<title>Let a receiver whose app is full keep what came, and say so</title>
<updated>2026-09-30T02:03:52Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-30T02:03:52Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=c9c0edf5a8fc9f79fff42064db09bc297e117a88'/>
<id>urn:sha1:c9c0edf5a8fc9f79fff42064db09bc297e117a88</id>
<content type='text'>
A link's delivery the app had no room for was handed over again at the
next turn: a receiver over its memory budget would refuse the same
records as fast as the owner could apply them. And its sender, seeing
records received but not stored for a second, sent the whole window
again every second.

Now a host says a delivery found it full (PureLinkDone.full). The
receiver keeps the records and hands them over again after a pause, 100
ms doubling to 500 ms, and meanwhile its STORED frames carry flag 2: the
app is full and what came is kept. A sender hearing it starts its
one-second wait for the save again, and sends none of it again. The
spec (012) says both sides; the pause is a local choice that must stay
under the sender's wait.

pure_link_done takes the PureLinkDone itself. test-link's new case keeps
the app full for 5 s: 12 hand-overs meanwhile, taken within 0.5 s of
having room, and no record sent again (21,640 without the flag).
</content>
</entry>
<entry>
<title>Say why a stream is refused (REFUSED), and try it again seldom</title>
<updated>2026-09-29T15:42:45Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-29T15:42:45Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=a06b652768a8643fe76efdc80a0c6eb729268fc5'/>
<id>urn:sha1:a06b652768a8643fe76efdc80a0c6eb729268fc5</id>
<content type='text'>
A receiver that took no records of a stream (a source the key may not
send as, no input of that name, an input of another shape) said nothing:
its sender heard them acknowledged, never stored, and sent them all
again every second, for ever, and its operator saw nothing. Now the
receiver answers REFUSED (0x0c: the names, and why), and the sender
sends no records for a second, then a packet of them to learn whether
they are taken now, the wait twice as long each time (64 s at most). A
refusal ends when that packet is acknowledged with no REFUSED beside, or
a record is stored. link.c says it once on stderr, as a wire says a
receiver does not take its sends; serve's input says which of the two
the app lacks.

test-link: each of the three is refused seven times in 90 s with nine
packets, and a stream refused until the app has its input goes on then,
all 200 records stored. check.py links a node to an input its receiver
lacks: said once, two packets in 2.5 s.
</content>
</entry>
<entry>
<title>Look for a link's receiver at once when the system says it cannot get there</title>
<updated>2026-09-29T14:10:40Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-29T14:10:40Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=44e9a395aaab92039ecd7c5fe546344be4a93e10'/>
<id>urn:sha1:44e9a395aaab92039ecd7c5fe546344be4a93e10</id>
<content type='text'>
A send that fails with no route, nobody at the port, or the network
gone (ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENETDOWN, EADDRNOTAVAIL)
now has the link look its receiver's name up again before its next
packet, not three unanswered probes later: a receiver moved away from an
address that is gone costs a sender one probe's wait, not three. Such a
failure no longer turns GSO off either (it said nothing of GSO). In the
check that moves a receiver, the sender sent 24 records again, not 243.
</content>
</entry>
<entry>
<title>Look for a link's receiver again when its probes go unanswered</title>
<updated>2026-09-29T14:02:46Z</updated>
<author>
<name>eunhhu</name>
<email>necpition205@gmail.com</email>
</author>
<published>2026-09-29T14:02:46Z</published>
<link rel='alternate' type='text/html' href='http://git.yeowoo.org/pure/commit/?id=a48c38d2a80efd146ba0f81cb46bac00c22297b6'/>
<id>urn:sha1:a48c38d2a80efd146ba0f81cb46bac00c22297b6</id>
<content type='text'>
A link resolved its receiver's name once, at its start: a receiver whose
store moved to another machine (another address under the same name)
was never found, and a sender whose own network changed kept a socket
that no longer went anywhere. Now, when three probes in a row go
unanswered, and at each probe after (a second apart at most), the link
looks the name up again and sends from a new socket connected there.
It looks before the probe goes, so the probe's answer comes to the new
socket (looking after it lost every answer, one socket after another).
A sender at rest does not look: only probes unanswered count.

make check moves a receiver (H3 of docs/design/011-pure-transport.md):
in namespaces of its own, the sender links to pure://receiver.test at
127.0.0.2; the receiver is killed, its store, key and memo copied, the
old address made unreachable, the name pointed at 127.0.0.3 and the
copy started there. Every order is applied once, and the moved receiver
makes no X25519.
</content>
</entry>
</feed>
