[rucksack-devel] Re: Rucksack, ECLM
Nikodemus Siivola
nikodemus at random-state.net
Thu May 18 10:45:09 UTC 2006
"Arthur Lemmens" <alemmens at xs4all.nl> writes:
>> If X was initialized as (make-instance 'my-p-thing :slot
>> (make-instance 'my-p-thing-2)), then by the time we tried to add the
>> root neither Lisp nor Rucksack would have the P-THING-2 around...
>
> Well... Lisp would still have the P-THING-2 around, if I understand
> your example correctly.
My intention was that the SLOT was proxied -- so Lisp would not have
a direct reference to it.
>>> Probably the best approach would be to have the GC automatically mark
>>> the in-memory copy of X as dead. Then we could signal an error (how
>>> about NECROPHILIA-NOT-ALLOWED-HERE?) for code that tries to do something
>>> with a dead object.
>>
>> I assume you mean "committing the transaction", not GC?
>
> No, I meant GC. The transaction has no way of knowing if X is dead or not.
> The only way to know that for sure is by doing the complete trace phase of
> the garbage collector (just checking the roots is not enough). That's
> obviously not something you want to do for each transaction commit.
Right. (Unless we maintained back-pointers for all pointers on disk,
but that sounds like a horrible idea.)
>> If legality of the add-root bit depends on the amount of garbage
>> collected in between.
>
> Yeah, that's unfortunate but there's nothing we can do about that. That's
> why I really think it's a "don't do that then" scenario. We can try to
> do some cheap checks to prevent this kind of stuff from happening, but
> we can't give any guarantee that you're protected from this. It's just
> too expensive. Unless I'm missing something, of course.
I'm not sure.
Starting from the top: to do anything at all with a persistent object
(ignoring non-persistent slots) you need to
1. Have the rucksack the object belongs to open.
2. Be in a transaction.
Could this "anything" be extended to holding a reference?
So that when a transaction exits, all in-memory objects with that
transaction-id become invalid, and trying to use them in the context
of another transaction would signal an error.
Then, the only way another transaction can legally get a hold of the
same object is by getting it afresh from the Rucksack.
That provides for the clear semantics and determinism, but is somewhat
inconvenient. No problem: indexed objects can be exempted from this
invalidation, as they are always reachable (and it is cheap to check
if an object is directly indexed). For other cases P-LET (call WITH-ROOTS)
can provide the same guarantee and convenience:
(WITH-ROOTS (X Y) ...) =>
(LET (X Y)
(LET ((#:TAIL-THUNK *ROOT-THUNK*)
(*ROOT-THUNK* (LAMBDA () (LIST* X Y (FUNCALL #:TAIL-THUNK)))))
...))
Now, both GC and transactions have access to additional in-memory
roots through the *ROOT-THUNK*. GC can use them just as regular roots.
Transactions just need to check if an object with an old
transaction-id is in the in-memory roots: if so, then using it is
fine. If not, an error is signalled.
Does that make sense?
(Strictly speaking, I think WITH-ROOTS needs to jump through a couple
of extra hoops to ensure single-assignment semantics, as otherwise you
can still get non-deterministic behaviour by removing an object from
the roots for the duration of GC and then putting it back. That won't
be too hard, though: nothing a symbol-macro can't handle.)
Cheers,
-- Nikodemus Schemer: "Buddha is small, clean, and serious."
Lispnik: "Buddha is big, has hairy armpits, and laughs."
More information about the rucksack-devel
mailing list