package
0.1.5
Repository: https://github.com/loopholelabs/silo.git
Documentation: pkg.go.dev

# Packages

No description provided by the author

# README

Silo protocol

Usage

To use Silo connections, you must first use ToProtocol and FromProtocol to serialize and deserialize storage requests to the protocol. Both of these take a Protocol argument. One such implementation of Protocol is ProtocolRW which can use any Reader and Writer to communicate.

So you can easily use a TCP connection, pipe, QUIC connection etc etc.

The protocol itself is a bidirectional packet based protocol.

There is a source (src), and a destination (dst) in a Silo connection for migration.

All packets contain a DeviceID, and a transactionID. Several Devices can be multiplexed down a single connection, and several operations for example WriteAt can operate concurrently.

Simple example

r1, w1 := io.Pipe()
r2, w2 := io.Pipe()

destDev := make(chan uint32, 8)

prSource := NewProtocolRW(context.TODO(), r1, w2, nil)
prDest := NewProtocolRW(context.TODO(), r2, w1, func(p Protocol, dev uint32) {
  destDev <- dev
})

sourceToProtocol := NewToProtocol(uint64(size), 1, prSource)

storeFactory := func(di *DevInfo) storage.StorageProvider {
  store = sources.NewMemoryStorage(int(di.Size))
  return store
}

destFromProtocol := NewFromProtocol(1, storeFactory, prDest)

There's a lot going on here, so lets go through what is happening. First we setup a couple of io.Pipe() to simulate some transport. We then wrap these pipes in NewProtocolRW(). The last argument here is a callback when a new device is detected (Any packet is received on a device not seen before). This callback can be used to start processing requests for that device for example. (In the example we just write to a channel).

Next up, we create a NewToProtocol(). This implements storage.StorageProvider and can be used as storage within silo. Any storage requests are then serialized and sent through the protocol.

Finally, we have a NewFromProtocol(), which deserializes storage requests. When a DevInfo is received, the storeFactory callback is called to initialize some storage.StorageProvider to handle subsequent storage requests.

Low level protocol

The first packet for a device should always be a DevInfo packet.

PacketDirectionDescription
DevInfosrc->dstProvides device information. eg size.
DirtyListsrc->dstList of blocks that are dirty and should be cache invalidated.
DontNeedAtdst->srcA range of data that we do not need. eg send if we write.
Eventsrc->dstEvent notifications for lock/unlock/complete. Things wait for an EventResponse.
EventResponsedst->srcConfirmation that the event has been acknowledged, and it's safe to continue.
NeedAtdst->srcA range of data that we need ASAP
ReadAtsrc->dstRemote read. Unused for migration.
ReadAtResponsedst->srcResult of the ReadAt
WriteAtsrc->dstRemote write. Migration data is sent here.
WriteAtResponsedst->srcResult of the WriteAt / confirmation.

Example migration conversation

The following would be a very minimal migration conversation

DirectionData
src->dstDevInfo size=1024
src->dstWriteAt offset=0 length=1024
dst->srcWriteAtResponse ok
src->dstEvent Complete

More complex conversation

DirectionDataComments
src->dstDevInfo size=4096Device information
src->dstWriteAt offset=0 length=1024First block of data
dst->srcNeedAt offset=2048 length=1024Prioritize this data
dst->srcWriteAtResponse okWrite ack
src->dstWriteAt offset=2048 length=1024Priority block of data
dst->srcWriteAtResponse okWrite ack
src->dstWriteAt offset=1024 length=1024More data
src->dstWriteAt offset=3072 length=1024More data
dst->srcWriteAtResponse okWrite ack
dst->srcWriteAtResponse okWrite ack
src->dstEvent Complete