Magma and block contexts and other quesitons.

Chris Muller afunkyobject at yahoo.com
Fri May 9 15:48:13 UTC 2003


Hi Derek,

> I get an error when trying to inspect the root of my repository.
> The following stack trace shows a BlockContext trying to materialize. 

I'll see about putting in something in that throws a MagmaUserError when trying
to *store* a block until Anthony's new image is ready, that way we won't be
able to get ourselves into this situation.

> Does this mean the repository is fried?

No, definitely not.  There are at least two ways to fix this.  The first way is
through client image inspectors and may be a little tedious.  The other
involves writing a script that makes use of MagmaFileTraverser and writes out a
new version of the repository.  Here is some guidance on both.

Fixing via a client image:

First, open and connect but do not try to get the root yet.  Instead, set your
read strategy to 1 level:

  mySession readStrategy: (MaBasicReadStrategy minimumDepth: 1)

This will only bring back one object at a time (except for collections which
always bring back a minimum of two), so unless the root IS a block (unlikely)
then you should be able to *inspect* the root.  Don't explore because that
forces proxy materializations due to the explorerStrings.

Look at the inspector, without selecting, decide which variable you think is
the Block.  If you KNOW its further down, you should be able to select that
variable and inspect again.

When you find the variable that is referencing the block, do NOT select it. 
Activating its printString will cause it's proxy materialization.  Instead, get
rid of it by typing this in the bottom of the inspector:

  mySession commit: [ sortBlock _ nil ]  "<-- replacing sortBlock with whatever
the name of your variable is, of course"

If you do accidently select the variable referencing the block, it'll blow
again.  If this happens, make a note of where you are, disconnect from the
repository and reconnect (sometimes I even close and reopen it just to be
safe).

Repeat this process until you've got them all nil'd out.  Once you think you've
eliminated all of the blocks, run a compress on the repository (see
MagmaRepositoryController utilities category).  Then open it again and check
your classesSet.  If BlockContext is still in there, then you didn't get them
all.

> There seems to be no way to inspect the contents of the repository other than
> inspecting the root of a session.  Is that right?  Is there anyway to 
> determine where the block context came from?

Yes, there is another way!  There is an easy-to-use utility in the MagmaServer
package that traverses the object file in a "batch" fashion.  It let's you
specify an internal iterator that takes *objectified buffers* as an argument
and you can do whatever you want.  Let me explain.

Everything object in a Magma database is stored in contiguous ByteArray in one
of three very specific formats.  One format for regular objects (such as a
Person or an OrderedCollection), one for Byte-objects (such as Strings and
ByteArray's) and one for a class definition.  When reading the repository file,
Magma doens't give you a ByteArray though, it gives you an instance of one of
three classes that allows you to easily access the fields in the ByteArray. 
Those classes are the three subclasses of MaObjectBuffer (stay with me, you do
actually care about this).  The major fields you care about in these buffers
will be the oid and classId.

If you look at MagmaCompressor, you can see how MagmaFileTraverser is used. 
You essentially have a allBuffersDo: [ :eachBuffer | ... ].  Using this, and
looking at how I write out the new file, you could effectively nil out any
BlockContext's this way.

How do you know which variables are Blocks?  By figuring out what classId was
assigned to BlockContext.  To do this, connect from your client image the same
way you always do, then explore the session.  Navigate to
mySession->serializer->classIdManager->idsByClass and look for BlockContext. 
Write that number down.  In your traverser, any buffers you encounter with that
classId will should not be passed to your write routine.  Additionally, you
need to note the oids of these buffers in your script and, possibly through a
second-pass, be sure any other buffers that reference those oids are then
pointing to the oid for nil (MaOidCalculator>>oidForNil) instead of the oid for
that Block.

You'll have to write a class to do this.  MagmaCompressor is your template
starting point.  Copy it to a new name and start by looking the #writeGraphs
method.  If you want to take this on, let me know and I can provide further
details once you've researched it.

There's no need to feel overly intimidated.  It really should not be too bad.

> I'm still trying to understand how this works.  What if you create a 
> repository from a root, to which you keep a pointer as a global variable.  
> Does that global variable now point to the repository object, or is it 
> pointing to a dead clone of the repository?

Magma supports three globals that you may reference directly in your model and
it will reconcile those with the real globals every time:

  Transcript
  Smalltalk
  Processor

Any other globals that you reference, including class variables, are persisted
in your image, and ignored by Magma.

If you wish to store them in the database, there are a couple of ways you could
keep it canonical with your global.  For example, one easy way would be to
implement #maPostmaterialize in the class of your global.  This method is
called just after the receiver has been materialized from a Magma repository
into the local image.  In that method, simply set your global to self.

Another way involves doing what I did with the afore-mentioned system globals. 
Take a look at the methods in the "*ma object serialization" category of
TranscriptStream.

Whew, I certainly hope this helps!  Let me know if I can be of further
assistance.

Regards,
  Chris

__________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo.
http://search.yahoo.com



More information about the Squeak-dev mailing list