3. GemStone Smalltalk changes and new features

Previous chapter

Next chapter

This chapter describes changes and new features important for programmers using GemStone Smalltalk, including:

Changes in Class and Method handling

Changes in Collections

Indexing changes

Socket Enhancements and new features

Numerics changes

GsEventLog

Changes in Errors and Error Handling

ProfMonitor changes

Other Additions and Changes

3.1  Changes in Class and Method handling

Changes to class variables requiring class versioning

Starting in v3.1, changing class variables did not require creating a new version of the class in the case of a class with only a single version. However, if multiple versions of the class existed, a new version was required when class variables were changed.

This restriction for multiple-versioned classes has been lifted.

Added Behavior method

The following method has been added:

Behavior >> classVarAt: aClassVar otherwise: defaultValue

Changes in class history for String and Symbol classes

In previous releases, the class histories for the various String and Symbol classes included the single and multiple byte variants, e.g., String’s classHistory included both DoubleByteString and MultiByteString. This was designed for the historical constraints, migration, and support for isKindOf: and similar operations.

As of 3.4, class histories conform to the new rule:

At most one entry in any class history shall have (Globals at: entry name) == entry

The various String classes now have a classHistory size of 1.

isKindOf: and similar methods have been reimplemented to avoid any change in behavior.

changeClassTo: handling of differently sized objects

The method Object >> changeClassTo: can be used to change the class of an object, including between classes with different numbers of named or indexed instance variables (indexed or varying instance variables are collection elements).

Previously, there was some undesirable behaviors in the cases when the number of and types of variables did not match:

  • Previously, when the number of named instVars in the target class was greater than the number of named instance variables in the receiver instance, nils were inserted for the additional named instVars, between the slots for the named and indexed values. Now, indexed values are moved into the named slots.
  • Indexed instVars remained on the receiver including cases in which the target class did not support indexed instance variables. Now, this is disallowed.
  • If the number of named instVars was fewer than the number of named instance variables in the target, then extra named instance variable values moved to indexed slots. Now, this is disallowed.

The previous behavior is available using Object >> legacyChangeClassTo:.

changeClassTo: now behaves according to the following rules:

  • If the instance has more total instvars (combined named and indexed) than the number of named instVars defined by the target class, then the target class must support indexed instVars (i.e. a collection). The overflow named or indexed instance variables will move into indexed instance variable slots.
  • If the instance has more total instvars than the number of named instVars defined by the target class, and the target class does not support indexed instance variables, it is an error.
  • If the target class defines more named instVars than the number of named instVars in the instance, and the instance has indexed instVars, then the data in the indexed instVars is moved into the otherwise empty named instVars slots. Any indexed instance variables beyond those required to fill the named instVars of the target class will remain indexed instance variables, with their offsets reduced by the number of indexed instance variables that became named instance variables
  • If the target class defines more named instVars than the total named and indexed instVars in the instance, then the extra slots are initialized to nil.

GsNMethod printOn:

GsNMethod now implements printOn:. As a result, displaying a GsNMethod now includes the class and selector of the method.

Pragmas

A pragma is a literal selector or keyword message pattern that occurs between angle brackets at the start of a method after any temporaries. For example:

<foo: 123 >
<foo: 5 bar: 'update'>
<bar>

Pragma keywords follow method selector syntax, but they are symbol literals within the method, not message sends. Pragmas are useful to provide metadata about methods and to support keyword searching.

While primitive directives in GemStone look like pragmas, they are not; and primitive: is a reserved word in the first pragma in a method.

Some pragma support was introduced for seaside-based environments in v2.x, but the implementation was incomplete and not usable in the base GemStone environment. (#43541).

Pragma class added

The Pragma class provides a way to find out information about pragmas. An instance of Pragma references the method that defines it, and the keyword and argument or arguments.

Sending GsNMethod >> pragmas will return an array of instances of Pragma.

Pragma class methods provide search capabilities. Pragma >> allNamed:in: returns a collection of all Pragmas with the given keyword in methods in the given class.

For other search methods, see the image.

Added ClassOrganizer subhierarchy report

The following method has been added:

ClassOrganizer >> subhierarchyReport:includeOops: 

For example:

topaz 1> run
ClassOrganizer new subhierarchyReport:  PositionableStream  
	includeOops: true
%
PositionableStream   19773697 ( collection position readLimit)
  ReadStream   19774721
  WriteStream   19775745 ( writeLimit)
    CypressMessageDigestStream   20292865
    ReadWriteStream   19776769
      FileStream   19777793 ( gsfile streamType)

Support for multiple execution environments

GemStone includes the ability to differentiate multiple execution environments, primarily with the intention to allow support for Ruby. These are distinguished using the envId: argument. GemStone Smalltalk execution uses environment 0.

In v3.4, some methods have been added to increase operability in environments 1 and above, although this is not fully supported for general use. Image methods with ruby-specific names have been removed.

Behavior/Module

The following methods have been added as variants of existing methods:

allSuperClassesForEnv:
compileMethod:dictionaries:category:intoMethodDict:
intoCategories:environmentId:
superclassForEnv:superclassForEnv:put: (only for use with environments > 0)

ClassOrganizer

ClassOrganizer now can be used for lookups in environments other then 0, using the class instance creation methods:

newForEnvironment: 
newWithRoot:forEnvironment: 
newWithRoot:forUserId:forEnvironment: 

PrivateObject

This is a new class, a subclass of nil (i.e., it does not inherit from Object). This is an abstract superclass for internal, hidden classes such as LargeObjectNode and NscNode.

Instance of subclasses of PrivateObject are normally for internal use only, but may be returned from some methods, such as reference path code. Only messages implemented in PrivateObject can be sent to instance of subclass of PrivateObject; other messages will signal a MessageNotUnderstood.

3.2  Changes in Collections

species, speciesForCollect, speciesForSelect

While usually collect:, select:, reject:, and similar methods return instances of the same kind of collection as the receiver, in some cases this is not correct. These overrides are normally handled by class-specific implementations of species, speciesForCollect, and speciesForSelect. In v3.4, the implementations have been cleaned up to move behavior into species* methods and remove unnecessary duplicates.

In addition, some RC classes incorrectly returned a result in an RC collection, rather than the equivalent non-RC collection, based on the return from speciesForCollect. (#46870)

Added RC Collection classes

The classes RcArray, RcIdentitySet, GsPipe, and RcPipe have been added.

RcIdentityBag has been reimplemented to be more efficient, with the name RcLowMaintenanceIdentityBag; both classes are available.

RcArray

The class RcArray is similar to Array, but no conflict occurs when multiple users add objects to an RcArray using specific methods. If a conflict with other update operations on the RcArray occur, the add is replayed so that the commit can succeed.

Only the following methods support concurrent updates

add: 
addAll:
at:put: (where no other session affects the element at the at: index)
size: (when size is increased)

RcLowMaintenanceIdentityBag

RcLowMaintenanceIdentityBag is a reimplementation of RcIdentityBag that avoids the use of per-session add and remove sets. This avoids the periodic manual maintenance that is required in some cases for RcIdentityBag. Like RcIdentityBag, there is no commit conflict with multiple sessions adding and a single session removing objects.

While the API is similar, the performance characteristics will vary between RcIdentityBag and RcLowMaintenanceIdentityBag. As for v3.4, both classes exist. In a future release, it is expected that RcIdentityBag will be replaced by RcLowMaintenanceIdentityBag, and the current implementation be renamed.

Due to the implementation, while you can create indexes on an instance of RcLowMaintenanceIdentityBag, in this release only indexes of type btreePlusIndex are supported, not legacyIndexes. See Indexes on new Reduced-conflict classes.

RcIdentitySet

For completeness with the other reduced-conflict classes, RcIdentitySet has been added. This provides an interface similar to Set, but using replay to handle commit conflicts. There is no commit conflict with multiple sessions adding and a single session removing objects.

Due to the implementation, while you can create indexes on an instance of RcIdentitySet, in this release only indexes of type btreePlusIndex are supported, not legacyIndexes. See Indexes on new Reduced-conflict classes.

GsPipe

The class GsPipe implements a first-in-first-out queue, with no conflict when a single session adds objects to the GsPipe, and only one session removes objects.

Internally, the GsPipe is implemented as a linked list of GsPipeElements. So, while most RC classes provide the reduced-conflict via either replaying conflicting transactions, or via per-session subcollections, GsPipe inherently has no conflict between operations at either end of the list.

RcPipe

The class RcPipe implements a first-in-first-out queue, with no conflict when multiple sessions add objects to the RcPipe, and only one session removes objects.

Internally, the RcPipe is implemented as a linked list of GsPipeElements. Unlike with GsPipe, if a conflict with an add by another session occurs, the add operation is replayed so that the commit can succeed. Only add: and operations that invoke add: are reduced-conflict.

Improved Concurrency for RC replay

Reduce-conflict classes use replay to resolve conflicts. Previously, all RC replay was serialized using a single lock, referenced by the global variable GemStoneRCLock.

Now, the Stone manages serialization so that only RC replays that conflict are serialized.

The global GemStoneRCLock has been removed, and the method System class >> waitForRcWriteLock:, which was intended for internal use in RC locking, has been removed.

The cache statistic RcRetryQueueSize is replaced by RcTransQueueSize.

Return type for remove: and add:

ANSI specifies that add: and remove: should return the argument, not the receiver; there were a small number of GemStone collection classes that did not respect this.

ANSI does not specify a return type for addAll: or removeAll:; most GemStone collection classes return the receiver for these cases.

The following methods have been updated in v3.4 to return the argument, not the receiver.

ExceptionSet >> add:
RcIdentityBag >> remove:
RcIdentityBag >> remove:ifAbsent:
Bag >> removeAll:
RcIdentityBag >> removeAll:
Set >> removeAll:

You should review your application code to ensure that any uses of the return value from these methods are updated.

Set arithmetic operators extended to Set and Bag

Set and Bag now implement intersection (*), union (+), and difference (-) operations. Previously these were only available in IdentityBag and its subclasses.

Added SequencableCollection method

The following instance method has been added to SequencableCollection:

indexOfSubCollection: aSubColl
Returns the index of the first element of the receiver where that element and the subsequent ones are equal to those in aSubColl. The search is begun in the receiver starting at 1.

Added Append classes for performance

The following classes provide optimized behavior for using Streams to assemble text.

AppendStream

AppendStream is a kind of Stream that is only for append, that is, performing writes at the end, and later retrieving the entire contents by sending contents. It is not "positionable", and implements only a limited set of Stream protocol. This allows it to be significantly faster for some common use cases, such as using a stream to compose complex text.

AppendableString

AppendableString is a kind of String that understands AppendStream protocol as well as String protocol. This allows use of Stream protocol without redirection through a stream, and may provide performance benefits for some uses.

While non-stream methods are inherited from String and not disallowed, they are not intended to be used.

This class may be subject to change.

Legacy stream added methods

The PortableStream hierarchy contains useful methods that were not previously available in the LegacyStream classes. The following methods have been added:

WriteStreamLegacy >> crlf
WriteStreamLegacy >> crtab
WriteStreamLegacy >> crtab:.
WriteStreamLegacy >> space:
WriteStreamLegacy >> tab:
ReadStreamLegacy >> nextMatchFor: 

Added String/UTF8 optimization and encoding

The following methods have been added for performance:

String >> addAllUtf8: aCharacterOrString

Utf8 >> addAllUtf8: aCharacterOrString
Append the UTF8 encoding of the argument to the receiver.

CharacterCollection >> addCodePoint: aSmallInteger

DoubleByteString >> addCodePoint: aSmallInteger

String >> addCodePoint: aSmallInteger

Unicode16 >> addCodePoint: aSmallInteger

Unicode7 >> addCodePoint: aSmallInteger
Append the character with the given codePoint to the receiver.
This is implemented a primitive for String, DoubleByteString, Unicode 7 and Unicode 16.

encodeAsUTF8IntoString

The following methods have been added:

String >> encodeAsUTF8IntoString
DoubleByteString >> encodeAsUTF8IntoString
QuadByteString >> encodeAsUTF8IntoString 

Previously there were private methods _encodeAsUTF8intoString, with the same behavior (note the capitalization changein i, as well as the underscore). These underscore versions remain for compatibility.

javaScriptEncode

Strings can now be encoded in Javascript, that is, with control characters escaped, by using the added method String>> and MultiByteString>>javaScriptEncode.

For details on the behavior of these methods, see the class methods String >> _javascriptCharacters and _javascriptEncode:.

Symbol parsing

Previously, expressions such as these:

#(a + b) #(a - 3b)

interpreted the binary operator and variables in various ways, or errored.

Per ANSI, this is illegal syntax, and are now disallowed. Now, only legal identifiers or keywords can omit the leading #. Legal binary selector symbols must include #, and creating other symbols requires both # and quotes.

For example, assuming the intention is to create three-element arrays, to create the equivalents of the above expressions now requires:

#(a #+ b)
#(a #- #'3b')

While this example is in a literal Array, the change involves all cases of symbol parsing.

Note that with this change, GemStone still does not conform entirely to ANSI, which would require a leading # for keywords (which have a final colon). Expressions such as #(a: 3) retain the same, non-ANSI behavior.

keywords

Symbol keywords changes

Symbol >> keywords parses the receiver by $:, returning an Array of the selector keywords with each substring including the trailing $:. Previously, this had a number of shortcomings.

  • If any of the terms (sequences of characters delimited by colons) was not a legal selector keyword, previously this method returned an empty array. Now, the results may include strings that are not legal selectors, such as keywords beginning with a digit or including characters such as $-.
  • Multiple colons were handled as if they were one colon. Now, each colon is treated as finalizing a term.
  • Previously, for a receiver with no colon (a unary selector), keywords appended a colon. (bug #46552)

CharacterCollection isKeywords more precise

CharacterCollection >> isKeyword continues to use a more precise ANSI definition of keyword, and only returns true for legal keyword selectors, not for unary or binary selectors. This also now detects some cases of illegal secondary keywords that previously did not return false. (#46696)

3.3  Indexing changes

The code that supports querying and indexing has been intensively reviewed and some parts have been reimplemented, and extensive testing has been added. Many bugs have been fixed, particularly in corner cases and in enumerated and set-valued indexes.

Terminology and parallel features

In v3.2, GemStone added a new indexing API the GsIndex/GsQuery API, to allow expansion on the historic API that uses UnorderedCollection methods and selectBlocks. Both APIs produce the same results, but many new features are not accessible from the historic API.

With v3.4, GemStone adds a new indexing internal structure, the BtreePlus index, based on a Btree+ implementation, to improve on the Legacy index internal structures based on simple Btrees and the RcIndexDictionary. Both internal implementations are available and (of course) produce exactly the same query results, but have different performance profiles and differences in default and error behavior.

Your application may use both the GsIndex/GsQuery API and the traditional API, and include both BtreePlus and Legacy internal structures. However, you cannot use both BtreePlus and Legacy indexing structures when creating multiple indexes on the same collection.

BtreePlus indexes

The data structures that supported indexing in previous releases included two data structures: Btrees, which contain the mappings for equality and allow range queries, and an RcIndexDictionary, which was used for mappings for identity queries and to map from the last element in the Btree node to the object itself.

v3.4 includes a new implementation of indexing data structures, the BtreePlus index. This btree+ based internal data structure includes the mappings that were previously done in the RcIndexDictionary, so no dictionary is needed.

The legacy indexing structures that were provided in previous releases are still available, and are the default for upgraded applications.

Using a BtreePlus indexes or a legacy index provides the same query results, but there are some differences in performance profiles and in default and error behavior. BtreePlus indexes perform best in combination with the new option optimizedComparisons, but there are more restrictions on the specific mixes of data types when optimizedComparisons are specified.

Optimized comparisons

Optimized comparisons is a new feature that is key to achieving the performance benefits of BtreePlus indexes.

Historically, equality indexes may have lastElementClass objects that are of different classes but which can be ordered against each other, such as Strings and Symbols, Floats and NaNs, or any object and nil. However, while less-than and greater-than queries are not a problem, these objects may never be equal; for example, both ('aa' <= #aa) and ('aa' >= #aa) are true, but ('aa' = #aa) is not true. To support these cases, extra message sends are done for equality indexes (the issue, obviously, does not arise for identity indexes).

To avoid the extra comparison costs when basic comparisons (e.g. =) are sufficient, you may now specify the index option #optimizedComparisons.

optimizedComparisons only apply to btreePlusIndexes, not legacyIndexes.

To use the optimizedComparison option, the values must be a kind of the last element class. Nil is not allowed as a last element class value, and the following rules apply:

  • For Float last element class, NaNs are not allowed as a value.
  • For String last element class, Symbols are not allowed as a value. Unicode strings are only allowed if the repository is in Unicode Comparison Mode.
  • For Symbol last element class, Strings are not allowed as a value.

When specifying optimizedComparison for the index, you will get an error if an element in the collection does not follow these rules; for example, if any element in the collection has a nil in the instance variable that the index specifies. If your collection legally may include nils in indexed instance variables, or if you mix Strings and Symbols, you cannot use the optimizedComparison option, and using legacy Indexes is likely to provide better performance.

Note that nils along the path, or missing instance variables as allowed by the existing GsIndexOptions optionalPathTerms setting, are unaffected by optimizedComparison. optimizedComparison specifies what is in the btreePlus holding the last element class values, while nils along the path affect other lookup structures.

lastElementClass

With legacy indexes, a lastElementClass of CharacterCollection, String, or Symbol (or the multi-byte equivalents) created indexes that allowed values of any of the above to be used as an indexed value. Specifying a lastElementClass of Unicode7, 16, or 32 created a unicode index with a collator; and in Unicode Comparison Mode, Unicode strings could be mixed with Traditional strings and symbols as indexed values. This behavior is the same for legacy indexes in v3.4.

However, using btreePlusIndex and optimizedComparison, mixing strings and symbols is disallowed. When using optimizedComparison, the meanings of the lastElementClass specification does distinguish between the "flavor" of the string.

When optimizedComparison is specified (either explicitly, or set as default), then:

  • Specifying a lastElementClass of String, DoubleByteString, or QuadByteString creates an optimizedComparison index that disallows symbols. If the repository is not in Unicode Comparison Mode, Unicode strings are also disallowed.
  • Specifying a lastElementClass of Symbol, DoubleByteSymbol, or QuadByteSymbol creates an optimizedComparison index that disallows strings.
  • Specifying a lastElementClass of Unicode7, Unicode16, or Unicode32 creates an optimizedComparison index that disallows symbols. If the repository is not in Unicode Comparison Mode, Traditional strings are also disallowed.
  • Specifying a lastElementClass of CharacterCollection creates a legacyIndex , not an optimizedComparison index. Since you cannot mix classes in an optimizedComparison index, the performance will be better with legacyIndex than with btreePlusIndex without optimizedComparison. However, note that you cannot mix legacy indexes and btreePlus indexes on a given collection.

The use of CharacterCollection is not recommended.

The following added convenience methods create an btreePlusIndex with optimizedComparison, regardless of any GsIndexOptions defaults, and restrict the lastElementClass values to the specified "flavor" of String:

stringOptimizedIndex: 
stringOptimizedIndex:options: 
symbolOptimizedIndex: 
symbolOptimizedIndex:options: 
symbolOptimizedIndex:collator:  
symbolOptimizedIndex:collator:options: 
unicodeStringOptimizedIndex:  
unicodeStringOptimizedIndex:options: 
unicodeStringOptimizedIndex:collator:  
unicodeStringOptimizedIndex:collator:options: 

Performance

btreePlusIndex and optimizedComparison are designed to significantly improve the performance of indexed queries, at the expense of somewhat less performant index updates. The performance improvements from these new indexed will depend on the performance profile of your application.

If the performance of indexed queries in your application is satisfactory, there is no need to change; the performance profile of legacyIndex is the same in v3.4, and overall performance is likely to be improved by other changes in v3.4.

If you are having issues with query performance, we recommend experimenting with the btreePlusIndexes and optimizedComparison, and verifying the performance benefits and ensuring that update performance does not create separate problems.

Note that btreePlusIndex without optimizedComparison is likely to be less performant than legacyIndexes.

GsIndexOptions changes

The instance of GsIndexOptions associated with every index has additional importance in this release, since it controls the use of btreePlusIndex or legacyIndex. One or the other of these options must always be set. In addition, optimizedComparison can only apply when btreePlusIndex is set, and is strongly recommended to get the performance improvements of the btreePlusIndex.

The way the defaults for GsIndexOptions are handled has been changed to provide more levels of control between the three basic types (legacyIndex, btreePlusIndex with optimizedComparison, and btreePlusIndex without optimizedComparison). The defaults also support the other options available in previous releases.

Given the multiple levels of default, the way instances are combined has been updated to support intuitively mathematical operators of +, -, and the new not operator.

Internally, GsIndexOptions has fields for each option that may be nil, true, or false. When instances are combined, the option fields that are true or false in the second operand take precedence.

When using default, the order of precedence is:

  • GsIndexOptions passed in with the options: keyword
  • default set using GsIndexOptions sessionDefault:
  • default set using GsIndexOptions default:. This is set to legacyIndex by upgrade.
  • "background" default of btreePlusIndex with optimizedComparison

not operator

The not operator has been introduced to improve clarity in specifying options.

For example, if the default is:

(GsIndexOptions btreePlusIndex + GsIndexOptions optimizedComparison)

you can turn off optimized compare using:

(GsIndexOptions optimizedComparison not)

Auto-unset of optimizedComparison

Since optimizedComparison is only valid for btreePlusIndexes, when a GsIndexOptions is set to legacyIndex (or btreePlusIndex not), then optimizedComparison is automatically turned off.

Initial default

The initial default for upgraded applications is:

(GsIndexOptions legacyIndex)

The initial default for new repositories is:

(GsIndexOptions btreePlusIndex + GsIndexOptions optimizedComparison)

Each instance of GsIndexOption is based on this default. So, for example, for a new repository, creating an instance of reducedConflict using the expression:

(GsIndexOptions reducedConflict)

the resulting GsIndexOptions instance would be:

(GsIndexOptions btreePlusIndex + GsIndexOptions optimizedComparison + GsIndexOptions reducedConflict

To avoid the default, you may explicitly specify the state for each option. This is easily done using the not operator.

Setting the default

You can change the initial default by executing either of the following:

GsIndexOptions default: aGsIndexOptions
Persistently change the default GsIndexOptions for all users. This method can only be executed by SystemUser.

GsIndexOptions sessionDefault: aGsIndexOptions
Set the default GsIndexOptions for this session only.

For example, if your initial default is:

(GsIndexOptions btreePlusIndex + GsIndexOptions optimizedComparison)

setting a session default to:

(GsIndexOptions optimizedComparison not + GsIndexOptions reducedConflict)

will result in GsIndexOptions instances being created by default as:

(GsIndexOptions btreePlusIndex + GsIndexOptions reducedConflict)

The btreePlusIndex stays the same, the optimizedComparison is removed, and the reducedConflict is added.

Indexes on new Reduced-conflict classes

This release introduced several new Reduced-Conflict (RC) classes, including two UnorderedCollection subclasses, RcIdentitySet and RcLowMaintenanceIdentityBag. In this release, you can create btreePlusIndexes on these classes, but you may not create legacyIndexes. This is due to the way conflict resolution is implemented in the new classes.

Queries on Array and other non-UnorderedCollections

It is now allowed to use instances of GsQuery to search over collections that do not support indexes, such as Array. Performance will be comparable to iterative search, but it allows managing queries similarly over various collection types and using the GsQuery syntax to flexibly build queries.

Most, but not all, of the collection classes may be queried using GsQuery. Class methods have been added to indicate if GsQueries are allowed:

_canCreateQueryOnInstances

Improved reliability and bug fixes

While the new substructure was developed and new features implemented, extensive additional testing has been added, and a large number of issues have been fixed; particularly relating to streamed queries, enumerated and set-value queries and queries involving nil values. These are not individually described here.

3.4  Socket Enhancements and new features

GsSocket adds support for SO_REUSEPORT

The SO_REUSEPORT socket option permits multiple AF_INET or AF_INET6 sockets to be bound to an identical socket address. This option may not be available on all OS revisions.

GsSecureSocket

GsSignalingSocket

The class GsSignalingSocket has been added, a subclass of GsSocket. This class signals kinds of Error, rather than returning nil, when a socket operation fails.

Errors now signalled, rather than methods returning false

GsSecureSocket is now a subclass of GsSignalingSocket.

Now when using GsSecureSocket, when an error occurs, the methods signal a SocketError or SecureSocketError rather than returning false.

This is true for most but not all error conditions; in particular, methods that return true or false, such as GsSecureSocket >> readWillNotBlock, will return nil on error.

GsSocket behavior is unchanged.

SSLv3

SSLv3 connections are no longer supported, as they are known to be insecure; only TLSv1 connections are currently supported.

Additional Peer Authentication Options

GsSecureSocket server sockets now support the verification modes SSL_VERIFY_FAIL_IF_NO_PEER_CERT and SSL_VERIFY_CLIENT_ONCE, which can be used when server certificate verification is enabled.

New methods in the image allow you to set options to an array that may include:

  • #SSL_VERIFY_FAIL_IF_NO_PEER_CERT -- if the client did not return a certificate, the TLS/SSL handshake is immediately terminated with a 'handshake failure' alert.
  • #SSL_VERIFY_CLIENT_ONCE -- only request a client certificate on the initial TLS/SSL handshake. Do not ask for a client certificate again in case of a renegotiation.

These options are only supported for server sockets; there are no verification options for client sockets.

The following methods have been added

GsSecureSocket class >> fetchCertificateVerificationOptionsForServer
Answers an Array of Symbols which represent the certificate verification options that can be used by server sockets.

GsSecureSocket class >> setCertificateVerificationOptionsForServer: anArray
Sets the certificate verification options for server sockets using an Array of Symbols. If anArray is empty then any previously set options are cleared. Certificate verification for server sockets must be enabled before executing this method. Only applies for sockets created after this method is executed.

GsSecureSocket >> fetchCertificateVerificationOptions
Answers an Array of Symbols which represent the certificate verification options that can be used by the receiver. Certificate verification options are only supported by server sockets.

GsSecureSocket >> setCertificateVerificationOptions: anArray
Sets the certificate verification options for the receiver, which must be a server socket, using an Array of Symbols. If anArray is empty then any previously set options are cleared. The receiver must enable certificate verification before this method is executed, and must use this method before the receiver attempts a connection with its peer.

The following are added protocol to check for the current status of verification:

GsSecureSocket class >> certificateVerificationEnabledOnClient
Answer true if certificate verification is enabled for client sockets.

GsSecureSocket class >> certificateVerificationEnabledOnServer
Answer true if certificate verification is enabled for server sockets.

GsSecureSocket >> certificateVerificationEnabled
Answer true if certificate verification is enabled on the receiver.

Methods have also been added to specify a certificate directory.

GsSecureSocket class >> useCACertificateDirectoryForClients: aDirectoryString
Specifies a directory where trusted certificate authority (CA) certificates in PEM format are located. The certificates in this directory will be used to authenticate certificates provided by servers during the SSL handshake. The directory may contain more than one certificate.

Certificates are loaded into the internal SSL state which is valid for the current session only; the SSL state is not committed to the repository. Has no effect on instances created before the method was called, nor on server sockets.

If successful, this method also enables certificate verification for client sockets as if the #enableCertificateVerificationOnClient method was called.

GsSecureSocket class >> useCACertificateDirectoryForServers: aDirectoryString
Specifies a directory where trusted certificate authority (CA) certificates in PEM format are located. The certificates in this directory will be used to authenticate certificates provided by client during the SSL handshake. The directory may contain more than one certificate.

Certificates are loaded into the internal SSL state which is valid for the current session only; the SSL state is not committed to the repository. Has no effect on instances created before the method was called, nor on client sockets.

If successful, this method also enables certificate verification for server sockets as if the #enableCertificateVerificationOnServer method was called.

Client certificate verification automatically enabled when CA certificate set

GsSecureSocket >> useCACertificateFileForClients: and useCACertificateFileForServers: now enable cerificateVerification; previously this required an additional step for clients.

SecureSocketError

The class SecureSocketError has been added, and is used for security errors signaled from GsSecureSocket.

SocketError asString

SocketError asString has been added, providing a printed version that is specific to SocketError.

HTTPS example

A https client example has been added, demonstrating a client SSL socket connection to https://google.com with full certificate verification enabled.

Connect with timeout

The following methods have been added, to allow a timeout to be specified on connect.

GsSecureSocket >> secureAcceptTimeoutMs: 
GsSecureSocket >> secureConnectTimeoutMs: 

3.5  Numerics changes

Random default change

The Random class is an abstract class, with actual random numbers generated by subclasses HostRandom, Lag1MwcRandom, and Lag25000CmwcRandom.

In previous releases, Random class methods new and seed: returned instances of Lag25000CmwcRandom. This implementation of random number generator took significant time to create initially, and was designed to be used where a series of reliably random numbers was needed. The large overhead of creation, however, made it unsuitable for cases in which a single random number was required, and a truly random number was not required. (#46990)

This has been changed in v3.4. Now, Random new will return an instance of HostRandom, and Random seed: returns an instance of Lag1MwcRandom.

For applications that have strict requirements for randomness, it is recommended to refer to the specific class directly, e.g. Lag25000CmwcRandom seed: .

FloatingPoint signalling Exceptions

For compliance with the IEEE 754 spec on floating point exceptions, starting with GemStone v3.0, certain floating point operations that signalled exceptions in v2.x instead returned an exception float, such as a NaN or Infinity. For example, dividing by 0.0 returned PlusInfinity rather than erroring. This can create potentially serious problems for applications that rely on exceptions to detect errors. (#46398)

Now, you may configure GemStone such that floating point operations that by default return the IEEE 754-specified ExceptionalFloat will instead signal an Exception.

The following are the symbols representing the kinds of errors for which exception signalling can be enabled:

  • #divideByZero
  • #overflow
  • #underflow
  • #invalidOperation
  • #inexactResult

To configure the set of errors for which Exceptions are signalled, use class protocol for FloatingPointError.

enableAllExceptions
Enable exceptions for all kinds of errors

enabledExceptions
Return an Array containing zero or more of the error symbols, reflecting the most recent call to #enableAllExceptions or #enableExceptions:

enableExceptions: symOrArrayOfSym
The argument may be one of the error symbols, or an Array containing zero or more of these Symbols , or nil. After an arithmetic operation when an exception occurs, it will check and if the corresponding symbol is enabled, it will signal a FloatingPointError, otherwise it will return the ExceptionalFloat.

Use care when enabling all exceptions, in particular enabling #inexactResults, as this may impact your application unexpectedly. When #inexactResults is enabled, expressions such as 1.0 / 3 will error.

Some non-floating point operations also use FloatingPointError, such as LargeInteger overflow. These exceptions are signaled regardless of FloatingPointError status, since there is no appropriate kind of number to return.

Added methods

In addition to this way of controlling exceptions, several other methods have been added:

Number, Float >> roundedNoFpe
Returns the Integer nearest in value to the receiver, ignoring any #inexactResult that might be enabled in FloatingPointError

Number, Float >> truncatedNoFpe
Returns the integer that is closest to the receiver, on the same side of the receiver as zero is located. ignoring any #inexactResult that might be enabled in FloatingPointError

Float >> noInexactResultDo: aBlock
Return value of executing aBlock, suppressing any FloatingPointError for #inexactResult that might occur.

Number >> isExceptionalFloat

Float >> isExceptionalFloat

DecimalFloat >> isExceptionalFloat

Invariance for non-special numeric instances

For numbers that are not specials, such as LargeIntegers, Fractions, and ScaledDecimals, some code paths could return an instance that was not invariant. (#46790). This does not apply to specials/immediate: SmallInteger, SmallDouble, and SmallFraction.

Now, all numbers are return as invariant.

#postCopy methods have been added to the non-special classes.

Obsolete methods

The following methods on BinaryFloat class have been replaced by the new FloatingPointException handling. While these methods are technically only deprecated in this release, they are no longer functional; you should update any references to these methods in your code as part of the upgrade to 3.4.

clearAllExceptions

clearException:

enabledExceptions

on:do:

operationException:

operationExceptions

raisedException:

raisedExceptions

roundingMode

roundingMode:

status

status:

trapEnabled:

3.6  GsEventLog

GsEventLog is a shared, reduced-conflict logging tool that allows multiple sessions to:

A GsEventLog class variable holds a instance of GsEventLog, which in turn holds a collection of log entries, which are instances of kinds of GsEventLogEntry. It is allowed for user applications to create custom subclasses of GsEventLogEntry.

Each event has a priority. Built in priorities are fatal, error, warning, info, debug, and trace; these are stored internally as integers.

The entries are stored in an instance of RcArray, allowing concurrent writes of log entries. Note that the order of elements is based on the order in which the commits occurred, while entry timestamps reflect the time at which the entry was created.

Adding events

GsEventLog may hold both application (user) events and system events. User entries can be added in two ways: class convenience methods such as logError:, logInfo:, etc., or by creating an instance of GsEventLogEntry and sending addToLog. A commit is required to make the log entry persistent.

System events should be added only by GemStone code. In this release, GemStone code does not write System events.

Querying and reporting

To create a string containing text representation of the entire contents, send

GsEventLog current report

To search for a subset of entries with particular attributes

(GsEventLog current entriesSatisfying: aBlock) report

Deleting events

GsEventLog is not reduced conflict for delete. It is recommended to lock the log using GsEventLog >> acquireGsEventLogLock. The lock is cleared automatically on commit.

You can clear all events using the following method:

GsEventLog current deleteAllEntries. 

By querying for specific methods, you can delete those methods using deleteEntry: or deleteEntries:

It is possible to restrict modifying or removing events. To do this, execute

GsEventLog entriesUnmodifiable 

After this is executed, new entries to the log are made invariant and the standard delete methods will not delete them. However, they are not protected from delete using private delete protocol.

System events are also protected from modification or deletion, other than using private delete protocol.

Example

topaz 1> run
[GsEventLog logDebug: 'About to perform divide by zero'.
 1 / 0.
 GsEventLog logDebug: 'After divide by zero'.
 true] 
	on: Error 
	do: [:ex | GsEventLog logObject: ex.  ex resume].
%
true
topaz 1> run
GsEventLog current report
%
'2017-07-13 16:36:44.3820  24198 Trace  About to perform divide by zero
2017-07-13 16:36:44.3821  24198 Trace  a ZeroDivide occurred (error
  2026), reason:numErrIntDivisionByZero, attempt to divide 1 by zero
  a ZeroDivide occurred (error 2026), reason:numErrIntDivisionByZero,
  attempt to divide 1 by zero
2017-07-13 16:36:44.3822  24198 Trace  After divide by zero

'

3.7  Changes in Errors and Error Handling

Message class added

The class Message has been added, for improved ANSI compatibility in handling does not understand. Previously, two-element arrays held the class and selector.

Now, doesNotUnderstand: is invoked with an instance of Message, and sending #message to MessageNotUnderstood error returns an instance of Message.

For compatibility, Message understands at:, size, and asArray, so existing code that expects a two-element array will continue to work correctly.

#rtErrInvalidArgClass now maps to ArgumentTypeError

Previously error 2283, invoked as #rtErrInvalidArgClass, mapped to ArgumentError; now this maps to ArgumentTypeError.

"statement has no effect" compiler errors

Previously code that included statements with no effect triggered a compiler warning and so did not compile. (#42510)

Now, a warning is triggered in this case for method compilation. Do-its may ignore the warning.

Unicode at:put: argument errors

The errors returned for invalid input to Unicode7 and Unicode16 at:put: arguments has changed. Previously these provided an OutOfRange error 2723 with an unclear message; now, they signal a ArgumentError 2004, or OffsetError 2003.

New errors

2518 #authErrStoreTrav /AUTH_ERR_STORE_TRAV
Smalltalk class: SecurityError
Error reported on an attempt to change the object security policy via store traversal.

2608 rtErrGroupAlreadyExists / RT_ERR_GROUP_ALREADY_EXISTS
Smalltalk class: ImproperOperation
Attempt to create a group when the group already exists.

2609 rtErrPrincipalAlreadyExists / RT_ERR_PRINCIPAL_ALREADY_EXISTS
Smalltalk class: ImproperOperation
Attempt to create a kerberos principal when the principal already exists

2755 rtErrGsSecureSocket / ERR_SecureSocketError
Smalltalk class: SecureSocketError (new in v3.4)

Certain security-related errors on a GsSecureSocket.

4016 #gsErrSslShutdown / GS_ERR_SSL_SHUTDOWN_ERR
Smalltalk class: SecureSocketError (new in v3.4)
Network error when switching from SSL to non SSL during login

4030 #errLostOtGci / ERR_LOST_OT_GCI
Smalltalk class: ImproperOperation
LostOt while waiting for a GCI command, and the transactionMode not transactionless

Changes in errors

2080 rtErrCantChangeClass, Illegal attempt to change the class of an object.
This error now includes a third argument: the reason why the change was illegal .

Removed errors

The following errors are no longer defined:

2050 repErrReplicateOnline

2037 classErrConstraintNotClass

2062 rtErrCannotChgConstraint (still referenced in image)

2107 objErrConstraintViolation (still referenced in image)

2132 classErrBadConstraint

2156 repErrReplicateNotMounted

2148 rtErrInvalidConstraintForMigration (was previously only referenced from image, now entirely removed)

2159 rtErrInvalidElementConstraintForMigration

2223 rtErrStrToPathConstraint

2308 rtErrBagNoConstraintAlongPath

2320 rtErrBadConstraintForMigration

2327 rtErrLastConstraintNotBoolean

2340 objErrDictConstraintViolation (still referenced in image)

Debugger Changes

Debugger frame printing of activations in blocks is simplified

Previously, the class of the block was included, which cluttered the view.

GsProcess added methods

For support for GCI application debugging, the following methods have been added:

GsProcess >> gciStepIntoFromLevel: 
GsProcess >> gciStepOverFromLevel: 
GsProcess >> gciStepThruFromLevel: 

These replace the deprecated GCIStep() and GciStep_() GCI functions.

GsProcess stack report line length

The lineLimit: keyword has been added to the most general form of stackReportToLimit*:

GsProcess >> stackReportToLevel:withArgsAndTemps:andMethods:includeSource:lineLimit:

Other stackReportToLevel* methods now use a default line size of 100.

Also, for the stackReportToLevel* methods that have the keyword includeSource:, this accepts an additional argument, #block, allowing display of the source for Executed Blocks.

3.8  ProfMonitor changes

Default interval changed

Previously, the default interval was 1 millisecond (defaultIntervalNs returned 1000000). Now, it is 0.5 milliseconds (i.e. 500 microseconds); defaultIntervalNs returns 500000.

ProfMonitor reporting change

The way ProfMonitor and ProfMonitorTree generate reports has been changed to allow more control over the specific reports. New methods have been added to support this; existing methods return reports as in previous versions.

A number of private reporting methods have been removed, and the flow of control through class methods has been cleaned up.

Report headers now include the reporting threshold.

Report Generation added methods

The following methods have been added:

ProfMonitor class >> monitorBlock:downTo:intervalNs:reports:
ProfMonitor class >> monitorBlock:reports:
ProfMonitor >> reportDownTo:reports:

These methods accept the additional keyword reports:, which allows you to specify an array of report symbols. These symbols are:

#samples - sample counts report is included in the resulting output.

#stackSamples - stack sampling report is included in the resulting output.

#senders - method senders report is included in the resulting output.

#objCreation - Enables object creation tracking; the object creation report is included in the resulting output.

#tree - causes ProfMonitorTree to be used for profiling, and the method execution tree report is included in the resulting output.

#objCreationTree- causes ProfMonitorTree to be used for profiling, and enabled object creation tracking; the object creation tree report is included in the resulting output.

ProfMonitor save and report

It is now supported to save an instance of ProfMonitor and perform the analysis and report later.

In order to perform the analysis later, it is necessary that the underlying raw results file not be deleted. The convenience monitorBlock* methods that return reports delete the raw data file; so to allow later analysis, use the new method ProfMonitor >> runBlock:.

For example,

run
UserGlobals at: #aProfMon put: 
  (ProfMonitor runBlock: [
    200 timesRepeat: [System myUserProfile dictionaryNames]	]).
%
commit
logout
login
run
aProfMon reportAfterRun
%
Renamed instance variable

The ProfMonitor instance variable rawSampleArray has been renamed to numSamples.

spyOn: removed

The deprecated method spyOn: has been removed.

3.9  Other Additions and Changes

Public objectForOop:

The private method _objectForOop: has been in use as a way to retrieve objects based on OOP. While "oop fishing" has risks, it is a useful tool for users who understand the issues and risks.

A public version, Object >> objectForOop:, has been added. This method differs from _objectForOop: in that it errors if no object with the given OOP exists. This avoids the ambiguity when resolving using nil’s OOP.

DateAndTime with ScaledDecimal seconds

By default, DateAndTime now returns an instance with the seconds as a SmallDouble, allowing arbitrary resolution (to system limits). However, this produced more digits of resolution than was needed.

The following method has been added:

DateAndTime class >> nowWithScale: anInteger
Creates a DateAndTime for the current time, using a ScaledDecimal with the given scale as the subsecond resolution. For example, using a scale of 3 will produce millisecond resolution.

To allow application-wide configuration of DateAndTime scale with a particular scale, the following new method can be used:

DateAndTime class >> setDefaultScale: anInteger
If this is executed as SystemUser with anInteger 0<= n <= 30000, this value will be used by subsequent DateAndTime >> now method invocations to create a DateAndTime with that given ScaledDecimal scale. If this was not set, or is set to nil, the behavior is unchanged, and DateAndTime >> now returns an instance with SmallDouble seconds.

performOnServer: and GsHostProcess optimization

These operations now use vfork() instead of fork(), and are much faster; one test demonstrated a 40x performance improvement.

GsBitmap added

The class GsBitmap has been added, encapsulating behavior of GemStone’s hidden sets. While GsBitmap can be considered as a collection and implements Collection protocol, it does not inherit from Collection. Instances of GsBitmap cannot be committed, and you cannot add temporary objects nor specials to a GsBitmap.

GsBitmaps are most useful when doing repository analysis. See GsBitmap for more information on using GsBitmaps.

ExecBlock

ExecBlock >> on:do: accepts zero argument do: block

The do: argument handling block passed to an on:do: expression may now be a zero argument block, as well as the usual one argument block.

Added cull:* methods

The methods cull:, cull:cull:, cull:cull:cull:, and cull:cull:cull:cull: have been added, for compatibility with Pharo and VW.

These are similar to value:, value:value:, etc, but allow for blocks that accept fewer arguments than the number of cull: arguments.

TestSuite debug

The following methods have been added:

TestSuite >> debug
TestCase >> debug
TestCase >> run

TestCase >> printString now produces the debug invocation of that case, as with GsTestCase.

Cypress subsystem preview added

Cypress is a dialect-independent solution for managing Smalltalk source code. FileTree is the GemStone version of this project.

A number of Cypress classes have been added. These are preliminary; future releases may make extensive changes to make internal use of these for code management.

 

Previous chapter

Next chapter