Last updated at 4:51 pm UTC on 16 January 2006
ImageSegments are a very fast binary object storage mechanism.
From the class comment - 3.3a-4769)
I represent a segment of Squeak address space. I am created from an array of root objects. After storing, my segment contains a binary encoding of every object accessible from my roots but not otherwise accessible from anywhere else in the system. My segment contains outward pointers that are indices into my table of outPointers.
When a segment is written out onto a file, it goes in a folder called image name_segs.
If your image is called "Squeak2.6.image", the folder "Squeak2.6_segs" must accompany the image whenever your move, copy, or rename it.
Whenever a Class is in arrayOfRoots, its class (aClass class) must also be in the arrayOfRoots.
See also Introduction to ImageSegments
There are two kinds of image segments.
Normal image segments are a piece of a specific Squeak image, and can only be read back into that image. The image holds the array of outPointers that are necessary to turn the bits in the file into objects.
To put out a normal segment that holds a Project (not the current project), execute (Project named: 'xxx') storeSegment.
The second kind of image segment is an Export Segment. It can be read into a different Squeak image. It does not have stay with your Squeak image. To create one:
(ImageSegment new copyFromRootsForExport: (Array with: Baz with: Baz class))
To create one for a project:
(Project named: 'Play With Me - 3') exportSegment.
To read it into another image:
- Select 'myFile.extSeg' in a FileList
- Menu 'load as project'.
It will install its classes automatically. If you need to see the roots array, it is temporarily stored in (SmartRefStream scannedObject).
- arrayOfRoots The objects that head the tree we will trace.
- segment The WordArray of raw bits of all objects in the tree.
- outPointers Oops of all objects outside the segment pointed to from inside.
- state (see below)
- segmentName Its basic name. Often the name of a Project.
- fileName The local name of the file. 'Foo-23.seg'
- endMarker An object located in memory somewhere after a segment that has just been brought in. To enumerate the objects in the segment, start at the segment and go to this object.
- userRootCnt number of roots submitted by caller. Extras are added in preparation for saving.
state that an ImageSegment may exist in...
arrayOfRoots, segment, and outPointers have been created by copyFromRoots:. The tree of objects has been encoded in the segment, but those objects are still present in the Squeak system.
- activeCopy (has been copied, with the intent to become active)
The segment is now the only holder of tree of objects. Each of the original roots has been transmuted into an ImageSegmentRootStub that refers back to this image segment. The original objects in the segment will all be garbageCollected.
- active (segment is actively holding objects)
The segment has been written out to a file and replaced by a file pointer. Only ImageSegmentRootStubs and the array of outPointers remains in the image. To get this far:
(ImageSegment new copyFromRoots: (Array with: Baz with: Baz class))
The segment has been brought back into memory and turned back into objects. rootsArray is set, but the segment is invalid.
The segment has been written out to a file, along with the text of all the symbols in the outPointers array, and replaced by a file pointer. This reduces the size of the outPointers array, and also allows the system to reclaim any symbols that are not referred to from elsewhere in the image. The specific format used is that of a literal array as follows:
#(symbol1 symbol2 # symbol3 symbol4 'symbolWithSpaces' # symbol5).
In this case, the original outPointers array was 8 long, but the compacted table of outPointers retains only two entries. These get inserted in place of the #'s in the array of symbols after it is read back in. Symbols with embedded spaces or other strange characters are written as strings, and converted back to symbols when read back in. The symbol # is never written out.
NOTE: All IdentitySets or dictionaries must be rehashed when being read back from this format. The symbols are effectively internal. (No, not if read back into same image. If a different image, then use #imported. -tk)
The segment is on an external file or just read in from one. The segment and outPointers are meant to be read into a foreign image. In this form, the image segment can be read from a URL, and installed. A copy of the original array of root objects is constructed, with former outPointers bound to existing objects in the host system.
(Any Class inside the segment MUST be in the arrayOfRoots. This is so its association can be inserted into Smalltalk. The class's metaclass must be in roots also. Methods that are in outPointers because blocks point at them, were found and added to the roots.
All IdentitySets and dictionaries are rehashed when being read back from exported segments.)
To discover why only some of the objects in a project are being written out, try this (Destructive Test). This breaks lots of backpointers in the target project, and puts up an array of suspicious objects, a list of the classes of the outPointers, and a debugger.
"Close any transcripts in the target project"
World currentHand objectToPaste ifNotNil: [
self inform: 'Hand is holding a Morph in its paste buffer:\' withCRs,
World currentHand objectToPaste printString].
PV _ Project named: 'xxxx'.
(IS _ ImageSegment new) findRogueRootsImSeg:
(Array with: PV world presenter with: PV world).
IS findOwnersOutPtrs. "Optionally: write a file with owner chains"
"Quit and DO NOT save"
When an export image segment is brought into an image, it is like an image starting up. Certain startUp messages need to be run. These are byte and word reversals for nonPointer data that comes from a machine of the opposite endianness. #startUpProc passes over all objects in the segment, and:
The first time an instance of class X is encountered, (msg _ X startUpFrom: anImageSegment) is sent. If msg is nil, the usual case, it means that instances of X do not need special work. X is included in the IdentitySet, noStartUpNeeded. If msg is not nil, store it in the dictionary, startUps (aClass -> aMessage).
When a later instance of X is encountered, if X is in noStartUpNeeded, do nothing. If X is in startUps, send the message to the instance. Typically this is a message like #swapShortObjects.
Every class that implements #startUp, should see if it needs a parallel implementation of #startUpFrom:.