Next: Operations on actormaps, Previous: Persistence Tutorial, Up: Persistence [Contents][Index]
When using the persistence mechanism you take a portrait of a graph, the graph has one or more roots. All object references starting from those root objects will be serialized, this even for graphs which contain cycle. Take the following graph:
A H <-- roots /|\ | / E \ J B F / \ C D
The root objects would be objects A
and H
.
In order for an object to have persistence support it must be able to create a self portrait of itself. The self portrait is a collection of all the data and capabilities an object has thats needed to restore itself. This can be done by creating a function will be called upon taking a portrait return a list containing all the portrait data. The data can include references to other local objects.
Lets take a really simple example which is just an object which has a name it’s known by and greets you:
(use-modules (goblins)) (define (^greeter _bcom our-name) (lambda (their-name) (format #f "Hello ~a, my name is ~a" their-name our-name)))
This object is not persistence capable, that is it does not currently
have a mechanism to describe itself to create the self portrait. Trying
to take a portrait of a graph with a non-persistence aware object will
result in an error. The easiest way to convert this to a persistence
aware object is to use the define-actor
macro:
(use-modules (goblins) (goblins actor-lib define-actor)) (define-actor (^greeter _bcom our-name) (lambda (their-name) (format #f "Hello ~a, my name is ~a" their-name our-name)))
That’s it! The define-actor
macro is probably good enough to
handle most use cases. There will however be cases where you need to be
a bit more explicit regarding serialization. The define-actor
macro takes all of the values it’s spawned with, and keeps them around
so that you can be re-spawned with those values, however there may be
times for example where you need to convert certain values to a
serializable form.
In cases where you do need to be more explicit and can’t rely on the macro, you can do this manually. To do this we can define a self-portrait function which is called when the persistence system is taking a portrait, this function is expected to return either a list of values or a versioned tagged list of values (more on versioning See Upgrading through persistence). Here’s the same greeter but manually specifying the self-portrait behavior:
(use-modules (goblins)) (define (^greeter _bcom our-name) (define (main-beh their-name) (format #f "Hello ~a, my name is ~a" their-name our-name)) (define (self-portrait) (list our-name)) (portraitize main-beh self-portrait))
The persistence system supports the following types:
(goblins abstract-types)
module)
(goblins abstract-types)
module)
(goblins ocapn ids)
Any other value of another type needs to be converted into one of the supported types above.
As mentioned above, the goblins persistence system can handle references to objects within the same actormap or vat, you simply include the refer when persisting. Let’s take a look at a greeter which does that, keeping track of the number of types its been called:
(use-modules (goblins) (goblins actor-lib cell)) (define-actor (^greeter* _bcom our-name number-of-times) (lambda (their-name) (let ((times ($ number-of-times))) ($ number-of-times (+ 1 times)) (format #f "Hello ~a, my name is ~a (called ~a)" their-name our-name times)))) (define* (^greeter bcom our-name #:optional [number-of-times 0]) (^greeter bcom our-name (spawn ^cell number-of-times)))
This example uses define-actor
with a seperate constructor which
“cellifies‘ the number-of-times and has a default argument. The
define-actor
will include both the name (a string, like before)
and a local reference to the cell object containing the number of times
called. This could have also been written a different way using the
manual, more explicit way, this exercise is left to the reader.
Next: Operations on actormaps, Previous: Persistence Tutorial, Up: Persistence [Contents][Index]