Keep-alive overview for GemStone sessions

A GemStone session sees the database as it was at the start of its current transaction. As long as a session keeps that old view, the stone has to keep the old versions of the objects it might still read, so the repository grows. A session that stays connected and idle for hours, for example one that was simply forgotten, therefore costs space for everybody.

The keep alive solves this from the image side: a background process that regularly aborts the idle sessions of a session registry, so that their view of the database moves forward. Optionally, it also logs out sessions that stayed connected for too long. It is implemented by GtGemStoneSessionKeepAlive Object << #GtGemStoneSessionKeepAlive traits: {TGtAnnouncer}; slots: { #registry . #delay . #shouldExit . #scheduleTask . #pollPromise . #cleanPostAction . #modifiedPostAction . #announcer . #notification . #loggedOutConnections }; sharedVariables: { #MaxKeepAlive }; tag: 'Registry'; package: 'GToolkit-GemStone-Pharo' ; every session registry has one.

Every 3 minutes (the poll interval, #selector defaultPollInterval ^ 3 minutes ) the keep alive looks at each connected session of the registry. The poll of a single session is done by GtGemStoneSessionKeepAlive>>#pollSession: pollSession: session shouldExit ifTrue: [ ^ self ]. session isRunning ifFalse: [ ^ self ]. GtGemStoneKeepAliveSessionPollStartedSignal new keepAlive: self; session: session; emit. (self canPollSession: session) ifFalse: [ ^ self skipSession: session ]. session keepAlive shouldStopAutoAborting ifTrue: [ ^ self pollSessionNoLongerAutoAborted: session ]. self keepSessionAlive: session. session keepAlive updateLogoutStateForNextPollIn: delay :

No uncommitted changes: the session is aborted. Nothing is lost, and the session now sees the current state of the database.

Uncommitted changes: the session is left alone, because an abort would throw the changes away. If it still has changes at the next poll (GtGemStoneKeepAliveSession>>#isDirty isDirty "Answer a boolean indicating whether the receiver's session is considered dirty, i.e. it has needed a commit for the last two keepAlive polls" ^ dirtyCount > 1 ), it appears in a notification, so that you can commit or abort it yourself.

Busy, or not in automatic transaction mode: the session is skipped and looked at again at the next poll (GtGemStoneSessionKeepAlive>>#canPollSession: canPollSession: session ^ session isBusy not and: [ session isAutoMode ] ).

The keep alive does not take care of a session forever. Each connector has a max keep alive , by default 60 minutes after the session connected (GtGemStoneSessionKeepAlive>>#maxKeepAlive maxKeepAlive "Answer the number of minutes to keep the session alive" ^ MaxKeepAlive ifNil: [ 60 ] ). What happens when it is reached depends on whether the connector has auto-logout enabled (it is off by default, see GtGemStoneGciConnector>>#initialize initialize super initialize. stone := 'gs64stone'. netldi := 'gs64ldi'. username := 'DataCurator'. password := 'swordfish'. gemstoneVersion := self class defaultGemStoneVersion. autoLogoutEnabled := false. logoutPostponable := false. logoutPostponeDuration := self class defaultLogoutPostponeDuration ):

Auto-logout off: the keep alive stops aborting the session. The session stays connected, and keeping its view up to date is up to you.

Auto-logout on: the session is logged out. The logout is announced one poll in advance (GtGemStoneKeepAliveSession>>#updateLogoutStateForNextPollIn: updateLogoutStateForNextPollIn: aDuration | nextPollTime wasLogoutPending | wasLogoutPending := self isLogoutPending. logoutRequestedByConnector := self isAutoLogoutEnabled and: [ session connector isLogoutRequestedFor: session ]. nextPollTime := self currentTime + aDuration. scheduledForAutoLogout := self isAutoLogoutDueAt: nextPollTime. logoutCause := self scheduledLogoutCause. scheduledForAutoLogout ifTrue: [ scheduledLogoutTime := nextPollTime. self recordOperation: statistics logoutSchedules ]. self announceLogoutPendingChangeFrom: wasLogoutPending ): the session shows up in orange in the notification and in the session lists, as logout pending . From there you can log it out right away or, if the connector allows it, postpone the logout (by default for 15 minutes, GtGemStoneGciConnector>>#defaultLogoutPostponeDuration defaultLogoutPostponeDuration ^ 15 minutes ). Note that a session is logged out even if it has uncommitted changes; those changes are lost.

These settings belong to the connector and are saved with it: maxKeepAlive, autoLogoutEnabled, logoutPostponable and logoutPostponeDuration on GtGemStoneGciConnector GtGemStoneConnector << #GtGemStoneGciConnector slots: { #stone . #netldi . #username . #password . #hostUsername . #hostPassword . #libraryPath . #gemstoneVersion . #autoLogoutEnabled . #logoutPostponable . #logoutPostponeDuration }; tag: 'Client'; package: 'GToolkit-GemStone-Pharo' .

Connection history

Each time a session connects, it starts a new connection record (GtGemStoneSessionConnectionRecord GtGemStoneAbstractSessionConnectionRecord << #GtGemStoneSessionConnectionRecord slots: { #sessionName . #connectionTime . #keepAlive . #disconnectionReason }; tag: 'Client'; package: 'GToolkit-GemStone-Pharo' ). The record holds when the connection started, what the keep alive did with it (aborts, changes found, postponements) and, once it is over, how it ended: closed by the user, logged out by the keep alive, or lost because the gem was stopped or the network went down. A lost connection is also reported in a notification. The records are kept in three places, so that a disconnect can still be traced afterwards:

The session keeps its current connection and its last 10 ended ones (GtGemStoneSession>>#maxEndedConnectionRecords maxEndedConnectionRecords ^ 10 , Connection history view).

The registry keeps the last 50 ended connections of all its sessions, including sessions that are no longer in the registry (GtGemStoneSessionRegistry>>#maxEndedConnectionRecords maxEndedConnectionRecords ^ 50 , Ended connections view).

The keep alive keeps the last 50 connections it logged out itself (GtGemStoneSessionKeepAlive>>#maxLoggedOutConnections maxLoggedOutConnections ^ 50 , Logouts view).

Inspect the session registry: the Keep alive view shows the state of every session (last poll, changes, time left before a logout), and the Sessions view lets you postpone a pending logout. The Keep alive view of a single session shows its details. The GemStone sessions card on the home page marks the sessions with a pending logout and can postpone them too. The examples in GtGemStoneSessionKeepAliveExamples Object << #GtGemStoneSessionKeepAliveExamples slots: {}; tag: 'Examples'; package: 'GToolkit-GemStone-Pharo' walk through each case step by step.

GtGemStoneSessionRegistry default