19. External Sessions

Previous chapter

Next chapter

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.

19.1 Overview

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.

GemStone includes:

While the API for these classes is similar, there are some differences, which are mentioned in the text.

 

19.2 External Sessions

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.

Setup the External Session

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.

Creating the External Session

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.

Default -- logging in to the same stone as the originating gem

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.

For example:

GsTsExternalSession newDefault
	username: 'Newton';
	password: 'gravity';
	yourself
Using NRS strings

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'
 
With GsNetworkResourceString
GsTsExternalSession 
		gemNRS: (GsNetworkResourceString 
			gemNRSForNetLDI: 'gs64ldi' onHost: 'santiam')
	stoneNRS: (GsNetworkResourceString 
		stoneNRSForStoneName: 'gs64stone' onHost: 'santiam')
	username: 'Newton'
		password: 'gravity'
When logging into a different version of GemStone

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.

You must use a method that specifies the GciTsLibrary version to be used, for example:

| sess |
sess := GsTsExternalSession 
	parameters: nil
  	library: (GciTsLibrary
     		newForVersion: '3.5.4'
     		product: '/lark/users/gsadmin/GemStone64_354').
sess 
	stoneNRS: '!#netldi:ldi_354!stone354';
	username: 'DataCurator';
	password: 'swordfish';
	gemNRS: '!#netldi:ldi_354!gemnetobject'.

Log in the External Session

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.

Executing Code

Code to be executed by the remote Gem can be passed as strings or blocks. These can be executed synchronously or asynchronously.

Code in Strings

To synchronously execute code contained in a string, use the method executeString:.

For example:

myExternalSession executeString: 
'SystemRepository fullBackupTo: '
	'/backups/gs/bkup20-08-23.dat'''. 
Code in Blocks

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.

Return Values

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.

Asynchronous Execution

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: aStringforkBlock: aNoArgBlockforkBlock: aOneArgBlock with: aValueforkBlock: 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 isResultAvailable answered 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.

Operations on remote objects

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.

Important caution on Export Set of remote session

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. These OOPs remain in the export set of the remote Gem, and will not be garbage collected, until that Gem is logged out. These OOPS can be removed manually from the export set using Hidden Set protocol.

Although 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.

Exceptions

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

19.3 NRS and Login Parameter Support

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.

For a Stone

  • body: the name of the Stone.
  • node: not needed for a remote Stone running on localhost. Otherwise, the name or IP address of the remote Stone’s node.
  • netldi: not needed if the NetLDI serving the remote Stone is running as gs64ldi. Otherwise the name or port of the NetLDI serving the remote Stone.

For example:

(GsNetworkResourceString new
   node: 'santiam';
   netldi: '51234';
   body: 'gs64stone';
   yourself) printString
'!@santiam#netldi:51234!gs64stone'

For a Gem

  • body: the name of the gem service (e.g. 'gemnetobject' or 'gemnetdebug'). Gem service arguments such as gemnetobject -C can be included here.
  • node: not needed if the Gem will run on localhost. Otherwise, the name or IP address of the node that the remote Gem will run on.
  • netldi: not needed if the NetLDI serving the remote Stone is running as gs64ldi. Otherwise the name or port of the NetLDI serving the remote Stone.
  • authorization: if the remote Netldi is not running in guest mode, the host userId and host password of the account that will own the remote Gem.
  • log: optional, specifies a log file for the remote Gem.
  • dir: optional, specifies a working directory for the remote Gem.

For example:

(GsNetworkResourceString new
   node: 'santiam';
   netldi: '51234';
   authorization: 'user@passwd';
   body: 'gemnetobject';
   yourself) printString
'!@santiam#auth:user@passwd#netldi:512345!gemnetobject'

Convenience methods for common arguments

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'.

19.4 Special Cases of External Sessions

Solo external sessions

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:

  • The extent must not part of a multi-extent repository
  • The extent file must either have read-only file permissions, or it will be exclusive-locked by the solo session.
  • The extent repository must have been previously cleanly shutdown by the Stone

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:

Example 19.1 Passing a custom extent to a solo login

| myExternalSession |
myExternalSession := GsTsExternalSession
   gemNRS: 'gemnetobject -C GEM_SOLO_EXTENT=$GEMSTONE/archive.dbf'
   stoneNRS: nil
   username: 'DataCurator'
   password: 'swordfish'.
myExternalSession loginSolo.
 

Primitive-based external sessions on AIX

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.

X509 external sessions

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.

Previous chapter

Next chapter