Crate hopper [] [src]

hopper - an unbounded mpsc with bounded memory

This module provides a version of the rust standard mpsc that is unbounded but consumes a bounded amount of memory. This is done by paging elements to disk at need. The ambition here is to support mpsc style communication without allocating unbounded amounts of memory or dropping inputs on the floor.

How does hopper work? Imagine that hopper's internal structure is laid out like a contiguous array:

[---------------|----------------|~~~~~~~~~~~. . .~~~~~~~~~~~~~~~~]
0               1024             2048

Between the indicies of 0 and 1024 hopper stores items in-memory until they are retrieved. Above index 1024 items are paged out to disk. Items stored between index 1024 and 2048 are temporarily buffered in memory to allow a single page to disk once this buffer is full. This scheme fixes the memory burden of the system at the expense of disk IO.

Hopper is intended to be used in situtations where your system cannot load-shed inputs and must eventually process them. Hopper does page to disk but has the same durabilty guarantees as stdlib mpsc between restarts: none.

Inside Baseball

Hopper's channel looks very much like a named pipe in Unix. You supply a name to either channel_2 or channel_with_max_bytes_3 and you push bytes in and out. The disk paging adds a complication. In private, the name supplied to the above two functions is used to create a directory under data_dir. This directory gets filled up with monotonically increasing files in situations where the disk paging is in use. We'll treat this exclusively from here on.

The on-disk structure look like so:

data-dir/
   sink-name0/
      0
      1
   sink-name1/
      0

You'll notice exports of Sender and Receiver in this module's namespace. These are the structures that back the send and receive side of the named channel. The Senders--there may be multiples of them--are responsible for creating "queue files". In the above, data-dir/sink-name*/* are queue files. These files are treated as append-only logs by the Senders. The Receivers trawl through these logs to read the data serialized there.

Won't this fill up my disk?

Maybe! Each Sender has a notion of the maximum bytes it may read--which you can set explicitly when creating a channel with channel_with_max_bytes--and once the Sender has gone over that limit it'll attempt to mark the queue file as read-only and create a new file. The Receiver is programmed to read its current queue file until it reaches EOF and finds the file is read-only, at which point it deletes the file--it is the only reader--and moves on to the next.

If the Receiver is unable to keep up with the Senders then, oops, your disk will gradually fill up.

What kind of filesystem options will I need?

Hopper is intended to work on any wacky old filesystem with any options, even at high concurrency. As common filesystems do not support interleaving small atomic writes hopper limits itself to one exclusive Sender or one exclusive Receiver at a time. This potentially limits the concurrency of mpsc but maintains data integrity. We are open to improvements in this area.

Structs

Receiver

The 'receive' side of hopper, similar to std::sync::mpsc::Receiver.

Sender

The 'send' side of hopper, similar to std::sync::mpsc::Sender.

Enums

Error

Defines the errors that hopper will bubble up

Functions

channel

Create a (Sender, Reciever) pair in a like fashion to std::sync::mpsc::channel

channel_with_max_bytes

Create a (Sender, Reciever) pair in a like fashion to std::sync::mpsc::channel