Advertisement
Guest User

Untitled

a guest
Feb 21st, 2017
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.14 KB | None | 0 0
  1. Unison computations can hop between nodes, can fail, can be forked to execute asynchronously, and can be supervised:
  2.  
  3. ```Haskell
  4. -- Promote a pure value to `Remote`
  5. Remote.pure : ∀ a . a -> Remote a
  6.  
  7. -- Sequencing of remote computations
  8. Remote.bind : ∀ a b . (a -> Remote b) -> Remote a -> Remote b
  9.  
  10. -- The current node where the computation is executing
  11. Remote.here : Remote Node
  12.  
  13. -- Transfer control of remainder of computation to target node
  14. Remote.transfer : Node -> Remote Unit
  15.  
  16. -- Explicitly fail a computation for the provided reason
  17. Remote.fail : ∀ a . Text -> Remote a
  18.  
  19. -- Sleep the current computation for the given duration
  20. Remote.sleep : Duration -> Remote Unit
  21.  
  22. -- Start running a remote computation asynchronously, returning
  23. -- a `Task` value that can be used for supervision
  24. Remote.fork : ∀ a . Remote a -> Remote Task
  25.  
  26. -- Halt a running task (and any running subtasks) using the provided `Cause`
  27. Task.stop : Cause -> Task -> Remote Unit
  28.  
  29. -- Obtain the `Cause` that caused a running task to complete
  30. Task.supervise : Task -> Remote (Remote Cause)
  31.  
  32. -- Create a duration from a number of seconds
  33. Duration.seconds : Number -> Duration
  34.  
  35. -- this is TBD
  36. type Cause = Error Text Node | Completed | Cancelled | Unresponsive Node
  37. ```
  38.  
  39. Unison computations can provision new nodes:
  40.  
  41. ```Haskell
  42. -- Like `Remote.spawn`, but create the node inside a fresh sandbox
  43. Remote.spawn-sandboxed : Sandbox -> Remote Node
  44.  
  45. -- Like `Remote.spawn-sandboxed`, but use the provided symmetric key
  46. -- to communicate with the returned `Node`
  47. Remote.spawn-sandboxed' : Key -> Sandbox -> Remote Node
  48.  
  49. -- Create a new node 'in the same location' as the current node, sharing
  50. -- current sandbox resources
  51. Remote.spawn : Remote Node
  52.  
  53. -- Like `Remote.spawn`, but use the provided symmetric key
  54. -- to communicate with the returned `Node`.
  55. Remote.spawn' : Key -> Remote Node
  56.  
  57. -- Statically provision a `personal-info : Node`
  58. node personal-info -- layout block starts here
  59. Sandbox 5% 10MB 3GB accept-from
  60.  
  61. -- TBD
  62. type Sandbox =
  63. Sandbox CPU% Memory Storage (∀ a . Node -> Remote a -> Remote a)
  64. ```
  65.  
  66. We can encrypt / decrypt any value at all:
  67.  
  68. ```Haskell
  69. -- Encrypt a value, requires `Remote` since we use random IV / nonce
  70. encrypt : ∀ a . Key -> a -> Remote (Encrypted a)
  71.  
  72. -- Decrypt a value, or return `None` if key is incorrect
  73. decrypt : ∀ a . Key -> Encrypted a -> Either DecryptionFailure a
  74.  
  75. -- `Key` is just a symmetric encryption key. We might generate keys via:
  76.  
  77. AES256.key : Remote Key
  78. Blowfish.key : Remote Key
  79. -- etc
  80.  
  81. -- TBD
  82. type DecryptionFailure = WrongKey | AlgorithmMismatch | IntegrityFailure
  83. ```
  84.  
  85. Unison programs have access to mutable variables, which also serve as a concurrency primitive:
  86.  
  87. ```Haskell
  88. -- Create an ephemeral `Box` on the current node; just a (GUID, Node) at runtime
  89. Box.empty : ∀ a . Remote (Box a)
  90.  
  91. -- Put a value into the box, or if the box is full,
  92. -- wait until a `Box.take` empties the box.
  93. Box.put : ∀ a . a -> Box a -> Remote Unit
  94.  
  95. -- Remove and return the value in the box, or if the box is empty,
  96. -- wait until a `Box.put` fills the box.
  97. Box.take : ∀ a . Box a -> Remote a
  98.  
  99. -- Like `Box.take`, but leaves the value inside the box
  100. Box.read : ∀ a . Box a -> Remote a
  101.  
  102. -- Read the current value inside the box or return `None` immediately.
  103. -- Also returns a setter which returns `True` if the set was successful.
  104. -- The `set` is successful only if the value inside the box has not
  105. -- otherwise changed since the read, so this can be used to implement
  106. -- "optimistic" atomic modifies.
  107. Box.access : ∀ a . Box a -> Remote (Optional a, a -> Remote Bool)
  108. ```
  109.  
  110. Unison can resolve references dynamically on a node:
  111.  
  112. ```Haskell
  113. -- Create a `Name`, which is a typed reference to a node-local value.
  114. Name.make : ∀ a . Remote (Name a)
  115.  
  116. -- Lookup the node-local value associated with the `Name`.
  117. Name.resolve : ∀ a . Name a -> Remote (Box a)
  118.  
  119. -- Declare `bob : Name Number` statically. The value bound to
  120. -- the `Name` does not survive node restarting.
  121. ephemeral name bob : Number
  122.  
  123. -- Declare `cluster-peers : Name (Vector Node)` statically. The current
  124. -- value of `cluster-peers` survives node restarting.
  125. durable name cluster-peers : Vector Node
  126. ```
  127.  
  128. Unison can make any value durable. `Durable` values are immutable:
  129.  
  130. ```Haskell
  131. -- Move any value from RAM to local durable storage
  132. Durable.store : ∀ a . a -> Remote (Durable a)
  133.  
  134. -- Synchronize any value to local durable storage, returning
  135. -- `True` if the give `Node` has that `Durable a` locally and
  136. -- the sync was successful.
  137. Durable.sync-from : ∀ a . Node -> Durable a -> Remote Boolean
  138.  
  139. -- Load a durable value into RAM, assuming it exists on the given node
  140. Durable.load-from : ∀ a . Node -> Durable a -> Remote (Optional a)
  141.  
  142. -- Returns a list of nodes that the Unison runtime believes could
  143. -- successfully `Durable.load-from` or `Durable.sync-from` for the
  144. -- given `Durable`.
  145. Durable.peers : ∀ a . Durable a -> Remote (Vector Node)
  146. ```
  147.  
  148. Lastly, we can declare foreign functions:
  149.  
  150. ```Haskell
  151. -- Declare `my-fn : Foreign (Number -> Remote Number)` statically
  152. -- Bindings for some of these foreign declarations would be done
  153. -- in some implementation-dependent way on Unison node container startup.
  154. foreign my-fn : Number -> Remote Number
  155.  
  156. -- Ask the current node if it has a binding for a `Foreign a`
  157. Foreign.ask : forall a . Foreign a -> Remote (Optional a)
  158. ```
  159.  
  160. ## Notes on semantics and implementation details
  161.  
  162. The `Task` returned by `Remote.fork` controls the entirety of the computation forked, including any subtasks forked. Stopping that `Task` stops anything that may be running underneath this fork.
  163.  
  164. Implementation notes on `Task.supervise`:
  165.  
  166. * At runtime, a `Task` value contains a `Node` reference where the `Task` was originally forked.
  167. * To implement `Task.supervise`, the runtime maintains at each node a `Map Task (Timestamp, Status, Optional Node)`, tracking for each task a timestamped last update for that task (when it was running on the current node), and an `Optional Node` if the computation was transferred elsewhere. This `Map` can be pruned using some ad hoc policy (like retain 30s of data or 5000 entries). `Task.supervise` then just chases the computation, following these transfer links until it obtains a "recent enough" status update for the computation. If a node is unresponsive or unreachable, this eventually leaks to an `Unresponsive` error being passed to the supervisor.
  168.  
  169. On node local storage:
  170.  
  171. * The association between a `Name` and a `Box` is _local to the node_. Conceptually, each node has its own durable and ephemeral storage. There is no storage concept exposed to Unison at any granularity beyond nodes (though of course you can write multi-node storage as regular Unison libraries). Nodes are isolated from each other and must communicate explicitly (even if the nodes are all spawned in a single sandbox).
  172. * The `durable name blah : Name Number` is somewhat analogous to a typed file name. It can be resolved on any node to a `Box Number`, and the state of that `Box Number` (whether it is empty or full) will survive node restarts.
  173. * The `node node-name` block declares a node statically, by proving a `Sandbox`.
  174. * The various `Durable` functions give some flexibility to Unison programs in how they resolve `Durable` values and where they load them from.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement