GemStone/S 64 Bit incorporates a number of classes that facilitate spawning and managing external sessions. This chapter describes these classes and how to use them
External Sessions
How to create and use external sessions
NRS and Login Parameter Support
describes how to setup the login parameters and define NRS strings
Special Cases of External Sessions
Special cases of external sessions, such as solo sessions.
External sessions allow you to execute Smalltalk code in separate Gems, which may run on different servers and log in as different users to different repositories, including repositories running different versions of GemStone. This allows you do to things such as partitioning work among multiple gems or managing separate repositories.
While the API for these classes is similar, there are some differences, which are mentioned in the text.
To use an external session, you must create an instance of the external session class, GsTsExternalSession, GsExternalSession, or a subclass; with the appropriate login parameters. Sending login to this instance creates a new Gem session that is logged into the Stone specified by the login parameters. This may be the same stone as the originating Gem or a different Stone.
You can then send messages to the instance of external session, which will be executed on the remote Gem.
After you have executed operations on the remote Gem, you must logout, to ensure the remote Gem is terminated and does not continue to use resources.
You cannot persist instances of kinds of AbstractExternalSession in the repository.
The login parameters you configure are the same as when logging in via topaz or other interfaces: the Stone’s NRS, the Gem’s NRS, and the userId and password that the external session will login as. If your login requires host username and host password, these are also required and are provided as part of the NRS arguments.
The Stone and Gem NRS may be provided as strings using GemStone’s standard NRS syntax, described in the System Administration Guide appendix C. For convenience, you may also use instances of the class GsNetworkResourceString, which makes it easier to compose complicated NRS Strings. See NRS and Login Parameter Support for classes that make composing NRS easier.
To create the external session, create an instance and specify instances of GsNetworkResourceString or NRS strings. The following examples show equivalents using GsNetworkResourceString and NRS strings.
GsTsExternalSession class >> newDefault creates a new instance of GsTsExternalSession, based on the login parameters of the originating Gem (with the exception of the password, which defaults to 'swordfish'). You then only have to apply any parameters that are different.
GsTsExternalSession newDefault
username: 'Newton';
password: 'gravity';
yourself
GsTsExternalSession class >> gemNRS:stoneNRS:username:password: allows you to specify the require login parameters. These can be strings or instances of GsNetworkResourceString.
GsTsExternalSession
gemNRS: '!@santiam#netldi:gs64ldi!gemnetobject'
stoneNRS: '!@santiam!gs64stone'
username: 'Newton'
password: 'gravity'
GsTsExternalSession
gemNRS: (GsNetworkResourceString
gemNRSForNetLDI: 'gs64ldi' onHost: 'santiam')
stoneNRS: (GsNetworkResourceString
stoneNRSForStoneName: 'gs64stone' onHost: 'santiam')
username: 'Newton'
password: 'gravity'
Logging into a Stone that is a running a different version of GemStone is not supported with GsExternalSession, only with GsTsExternalSession, and is only supported with a limited number of recent GemStone versions. Logging into a different version of GemStone also requires that you have gcc/g++ installed on the originating node.
You must use a method that specifies the GciTsLibrary version to be used, for example:
myExternalSession := GsTsExternalSession
parameters: nil
library: (GciTsLibrary
newForVersion: '3.6.6'
product: '/lark/users/gsadmin/GemStone64_366').
myExternalSession
stoneNRS: '!#netldi:ldi_366!stone366';
username: 'DataCurator';
password: 'swordfish';
gemNRS: '!#netldi:ldi_366!gemnetobject'.
Using a one-time password allows you to login a second session without including the password in code; a temporary password is granted based on the current logged-in user’s authentication. This feature is described in detail in the System Administration Guide.
One-time password requires that the logged-in user have the OneTimePassword privilege. It is possible to login as a different user than the currently-logged in user; however, this requires that the other userId be on an allowlist.
The temporary password is created with a time limit, and then immediately passed to the login code. The one-time password is only usable for a single login.
To use this password to login an external session, for example:
tempPW := GsCurrentSession currentSession
createOnetimePasswordValidForSeconds: 30.
myExternalSession := (GsTsExternalSession newDefault)
onetimePassword: tempPW;
yourself.
To login, send #login to the configured external session:
myExternalSession login
Login creates a remote Gem session that is logged in and in transaction in the specified Stone, either the same Stone as the originating Gem session, or a different Stone. If the remote Gem is logged into a Stone that is in active use, you must manage the Gem appropriately to avoid creating a commit record backlog in that Stone; avoid leaving remote Gems logged in and idle, and ensure that the code you execute commits or aborts regularly.
To logout, send #logout to the logged-in external session:
myExternalSession logout.
Code to be executed by the remote Gem can be passed as strings or blocks. These can be executed synchronously or asynchronously.
To synchronously execute code contained in a string, use the method executeString:.
myExternalSession executeString:
'SystemRepository fullBackupTo: '
'/backups/gs/bkup23-08-08.dat'''.
What is actually sent to the remote Gem is always in the form of a String, but methods are provided that accept blocks containing the code to execute in the remote Gem. The source strings for these block will be passed to the remote Gem. This allows Smalltalk tools to manage the source, detect senders, and so on, which is not possible with strings.
To use blocks, the blocks must be able to compile in both the originating Gem and the remote Gem in which you intend them to execute, although the block’s code is not necessarily meaningful in the originating session. Any variable resolution, etc. in the blocks will be resolved again in the environment of the remote Gem when the block is compiled after being transmitted as a string, and if the variables cannot be resolved in the remote Gem, it will result in an error.
Code in block can also be executed synchronously or asynchronously.
To synchronously execute code contained in a block, use:
executeBlock: aNoArgBlock
executeBlock: aOneArgBlock with: aValue
executeBlock: aTwoArgBlock with: aValue with: anotherValue
executeBlock: aBlock withArguments: aCollectionOfValues
These methods execute the source code contained in the given block, and return the result of executing that code.
When passing arguments to the block, the arguments values must be objects for which the printString allows the correct object state to be recreated in the remote session. This is true for all objects, including specials, strings, integers and floats; use caution to avoid unexpected conversion or loss of information, as well as errors.
After code is executed in the remote Gem, the result is returned to the originating session.
If the result of the expression is a special (Character, Boolean, SmallInteger, SmallFloat, etc.), or a String, Symbol, or ByteArray, the results are converted into the appropriate object in the originating Gem.
Expressions that return another type of object will return an Array containing the OOP of the result, the OOP of the class of the result, and the size of the result (for GsExternalSession, only the OOP of the result is returned). This should be avoided, except when performing additional remote operations on returned OOPs. The returned OOP is for the value of the result in the remote Gem, which may not exist or be resolvable in the originating Gem; and OOP lookup has an inherent risk of unexpected results.
When the result is not a special, then the OOP of the result is placed in the ExportSet of the remote Gem. See Important caution on Export Set of remote session.
Since the evaluation is done in a separate Gem process, any transient changes in the remote Gem are not visible in the originating Gem. In order for persistent changes in the remote Gem to be visible to the originating Gem, the remote Gem must commit the changes, and the originating Gem must abort.
The executeString: and executeBlock: methods block the originating Gem until execution completes. To execute the remote code asynchronously and return control immediately to the originating Gem, the following equivalent methods are available:
forkString: aString
forkBlock: aNoArgBlock
forkBlock: aOneArgBlock with: aValue
forkBlock: aTwoArgBlock with: aValue with: anotherValue
When you execute asynchronously, an external call is in progress, and the methods you can invoke on the remote session are limited:
isResultAvailable
Check whether the current call in progress has finished and save the result if it has.
lastResult
Answer the result received when the last isResultAvailableanswered true, which includes after a waitForResult operation completed.
waitForResult
Wait for the external Gem to complete the current operation.
waitForResultForSeconds: numSeconds
Wait up to numSeconds seconds for the external Gem to complete the current operation.
waitForResultForSeconds: numSeconds otherwise: aBlock
Wait up to numSeconds seconds for the external Gem to complete the current operation. If the operation does not complete within that time, answer the result of evaluating aBlock.
If you perform a remote operation that returns an OOP, you can send specific selectors to that remote object by OOP.
send: selector to: anOop
Send the given selector to the object in the external session with the OOP anOop.
send: selector to: anOop withArguments: anArrayOfValues
Send the given selector to the object represented by the given OOP, which is an OOP in the external session, and pass the Array of arguments.
The OOPs of the arguments are passed to the remote Gem. These arguments must be specials, or persistent objects that exist on both the calling and remote sessions, otherwise it will result in an error.
For objects other than specials (Integers, Characters, etc.) that are returned by the remote Gem, the remote Gem adds these objects to its export set. This includes Strings and other byte collections, Exceptions returned by the remote Gem, and other objects that are returned as OOPs.
Strings and similar byte-format results and exceptions are converted into new String (or appropriate) instances in the calling Gem (with a new OOP); the OOP of the original String on the remote Gem remains in the external Gem’s export set, for logins using GsExternalSession. When using GsTsExternalSession, in many cases the OOPs are released from the export set automatically.
Otherwise, these OOPs remain in the export set of the remote Gem, and will not be garbage collected, until the remote Gem is logged out.
These OOPS can be removed manually from the export set using GsTsExternalSession >> releaseOop: or releaseOops:. The export set can be examined using (GsBitmap newForHiddenSet: #PureExportSet) on the remote Gem.
The class GciError and GciLegacyError are provided to represent errors during remote execution. If the code being executed on the remote session encounters an exception, this is raised as a GciError in the calling session, or a GciLegacyError if using GsLegacyExternalSession.
Since remote debugging is not possible with this interface, the stack of the error is included with the error description.
For example, given the following code which triggers an error on the remote session:
result := [myExternalSession executeString: '1/0']
on: GciError
do: [:ex | ex description].
The result in the calling session will be:
GciError: a ZeroDivide occurred (error 2026),
reason:numErrIntDivisionByZero, attempt to divide 1 by zero
1 AbstractException >> _signalWith: @5 line 25
receiver size:0 a ZeroDivide occurred (error 2026),
reason:numErrIntDivisionByZero, attempt to divide 1 by z
inCextensionArg nil
res nil
.t1 size:0 a ZeroDivide occurred (error 2026),
reason:numErrIntDivisionByZero, attempt to divide 1 by z
2 AbstractException >> signal @2 line 47
receiver size:0 a ZeroDivide occurred (error 2026),
reason:numErrIntDivisionByZero, attempt to divide 1 by z
.t1 size:0 a ZeroDivide occurred (error 2026),
reason:numErrIntDivisionByZero, attempt to divide 1 by z
.t2 nil
3 Number >> _errorDivideByZero @6 line 7
receiver 1
.t1 size:0 a ZeroDivide occurred (error 2026),
reason:numErrIntDivisionByZero, attempt to divide 1 by z
.t2 size:0 a ZeroDivide occurred (error 2026),
reason:numErrIntDivisionByZero, attempt to divide 1 by z
4 SmallInteger >> / @6 line 7
receiver 1
aNumber 0
.t1 1
5 Executed Code @2 line 1
receiver nil
.t1 1
.t2 0
6 GsNMethod class >> _gsReturnToC @1 line 11
receiver oop:144897 GsNMethod
GemStone logins require a number of parameters. The Stone name, and the Gem service, are specified in the form of a Network resource string, or NRS. NRS includes a number of features; the NRS syntax is documented in theSystem Administration Guide, Appendix C.
While you may compose strings in standard NRS syntax for your external session logins, if you are unfamiliar with NRS syntax, the GsNetworkResourceString class provides a way to compose sophisticated NRS strings by specifying the individual building blocks.
The NRS Strings to specify a Stone are different than the strings used to specify a Gem service. The class GsNetworkResourceString supports variables for both sets of arguments; you will need to pass in the correct arguments for a Stone or Gem service.
(GsNetworkResourceString new
node: 'santiam';
netldi: '51234';
body: 'gs64stone';
yourself) printString
'!@santiam#netldi:51234!gs64stone'
(GsNetworkResourceString new
node: 'santiam';
netldi: '51234';
authorization: 'user@passwd';
body: 'gemnetobject';
yourself) printString
'!@santiam#auth:user@passwd#netldi:512345!gemnetobject'
There are a number of class methods that allow you to pass in specific required elements of an NRS. In addition to these specific listed methods, see the image for other variants.
gemNRS
Creates a Gem NRS that uses the default Gem script, which will expect to find gs64ldi on localhost; the equivalent of 'gemnetobject'
gemNRSForNetLDI: nameOrPort onHost: gemhostname
Creates a Gem NRS to run the Gem process on the host named gemhostname and with the NetLDI of nameOrPort with the standard gem script gemnetobject; the equivalent of '!@gemhostname#netldi:nameOrPort!gemnetobject'
stoneNRS
Creates a Stone NRS for a Stone named gs64stone, which should be running on localhost.
stoneNRSForStoneName: aStoneName onHost: stoneHostName
Creates a Stone NRS for aStoneName, which should be running on stoneHostName; the equivalent of '!@stoneHostName!aStoneName'.
Using a "solo" session, you can perform most GemStone operations without accessing a Stone. An external session can be logged in solo either on the same host or another host and does not have a login to any stones, regardless of a Stone name pass into the NRS for gemstone.
By default, solo sessions use the read-only empty distribution extent; this can be configured to use another extent file, provided the following are true:
To login solo, the only thing necessary is to send loginSolo rather than login. Note that the login parameters include the stone name, but this is ignored.
The configuration parameter GEM_SOLO_EXTENT specifies the extent file to be used by a Solo session. This defaults to the clean, read-only extent within the distribution, $GEMSTONE/bin/extent0.dbf. You can pass in another extent file by specifying the -C argument to gemnetobject. For example:
GsExternalSession uses the FFI GciLibrary to implement its functionality. On platforms on which the FFI GCI library cannot be used, instances of GsLegacyExternalSession provides external sessions. AIX is the only known environment where this class must be used.
The classes GsTsX509ExternalSession and GsX509ExternalSession, along with GemStoneX509Parameters, allow you to create an external session login using X509-Secured GemStone. See the GemStone/S 64 Bit X509-Secured GemStone System Administration Guide for details on how to set this up.