Skip to content

Commit

Permalink
Merge pull request #18 from GemTalk/normg-issue-17
Browse files Browse the repository at this point in the history
Fix various issues
  • Loading branch information
nrgiii authored Dec 23, 2024
2 parents 3575de4 + e9dd311 commit 78f7581
Show file tree
Hide file tree
Showing 23 changed files with 815 additions and 153 deletions.
17 changes: 17 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Version 1.1, December 22, 2024

## GemStone version 3.7.1 or later is now required. 3.7.0 and 3.6.x are no longer supported.

## Issues Fixed in 1.1:

### issue 17: Support fork and detach semantics
Add support for "execute and detach" semantics. This allows the FFI to "fork" code to run on the server and tells the gem to keep running if the client logs out and/or closes the socket.

### issue 16: Need smalltalk logic to call thread safe library GciTsNbLogout
Add GsSession>>logoutNbNoError method to call GciTsNbLogout(). This method causes an immediate logout without waiting for a response from the gem.

### issue 12: Should GsSession>>logout signal an error if not logged in?
This was a bug. GsSession>>logout now raises an error if the session is not logged in. To avoid the exception, use #logoutNbNoError or #logoutNoError.

### issue 5: SparkleFFI should trim white space on strings passed to C that are used in the NRS
Remove whitespace from stone, netldi, host, logPattern, dirPattern .
58 changes: 32 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,55 @@
GemStone GCI access via Pharo FFI

## Prerequisites

### Version 1.1
**GemStone version ==3.7.1== or later is now required!**

Tested on Pharo 9, 10, 11 on Windows and Linux. Other Pharo versions/platforms will probably work but might not.

Installation instructions assume that you have registered SSH Keys with your GitHub account. See [Connecting to GitHub with SSH](https://help.github.com/articles/connecting-to-github-with-ssh/) for more information.

You must have git installed: [git setup](https://help.github.com/articles/set-up-git/)

You must have access to the GemStone client libraries for 3.6.x or 3.7.0 for the client platform you're running on .
You must have access to the GemStone client libraries for 3.7.1 or later for the client platform you're running on .
The build step [slow|fast]clientlibs generates a zip file containing these libraries in the correct directory structure.

## Installation

If you are installing Sparkle, it will automatically install PharoGemStoneFFI, and there is no need to perform an manual install of PharoGemStoneFFI. See [Sparkle on github](https://github.com/GemTalk/Sparkle); the Installation Guide is under Documentation.

### Client Library Installation
Choose a location for the client library files and copy the client library zip file to that location. ClientLibs for Alpha5 are available here:
https://downloads.gemtalksystems.com/pub/GemStone64/3.7.0-Alpha5/GemStoneClientLibs3.7.0-x86.Windows_NT.zip
https://downloads.gemtalksystems.com/pub/GemStone64/3.7.0-Alpha5/GemStoneClientLibs3.7.0-x86_64.Linux.zip
Choose a location for the client library files and copy the client library zip file to that location. ClientLibs are available here:
https://downloads.gemtalksystems.com/pub/GemStone64/3.7.1/GemStoneClientLibs3.7.1-x86.Windows_NT.zip
https://downloads.gemtalksystems.com/pub/GemStone64/3.7.1/GemStoneClientLibs3.7.1-x86_64.Linux.zip

unzip the zip file into a directory named clientLibs.

The examples below show installing on Windows under cygwin, but the process is similar for Linux.
```
$ mkdir clientlibs
$ cd clientlibs
$ cp installdir/GemStoneClientLibs3.7.0-x86.Windows_NT.zip .
$ unzip GemStoneClientLibs3.7.0-x86.Windows_NT.zip
Archive: GemStoneClientLibs3.7.0-x86.Windows_NT.zip
creating: 3.7.0/
creating: 3.7.0/32bit/
inflating: 3.7.0/32bit/libgcirpc-3.7.0-32.dll
inflating: 3.7.0/32bit/libgcirpc-3.7.0-32.pdb
inflating: 3.7.0/32bit/libgcits-3.7.0-32.dll
inflating: 3.7.0/32bit/libgcits-3.7.0-32.pdb
inflating: 3.7.0/32bit/libssl-3.7.0-32.dll
inflating: 3.7.0/32bit/libssl-3.7.0-32.pdb
inflating: 3.7.0/32bit/vcruntime140d.dll
creating: 3.7.0/64bit/
inflating: 3.7.0/64bit/libgcirpc-3.7.0-64.dll
inflating: 3.7.0/64bit/libgcirpc-3.7.0-64.pdb
inflating: 3.7.0/64bit/libgcits-3.7.0-64.dll
inflating: 3.7.0/64bit/libgcits-3.7.0-64.pdb
inflating: 3.7.0/64bit/libssl-3.7.0-64.dll
inflating: 3.7.0/64bit/libssl-3.7.0-64.pdb
inflating: 3.7.0/64bit/vcruntime140d.dll
inflating: 3.7.0/64bit/vcruntime140_1d.dll
$ cp installdir/GemStoneClientLibs3.7.1-x86.Windows_NT.zip .
$ unzip GemStoneClientLibs3.7.1-x86.Windows_NT.zip
Archive: GemStoneClientLibs3.7.1-x86.Windows_NT.zip
creating: 3.7.1/
creating: 3.7.1/32bit/
inflating: 3.7.1/32bit/libgcirpc-3.7.1-32.dll
inflating: 3.7.1/32bit/libgcirpc-3.7.1-32.pdb
inflating: 3.7.1/32bit/libgcits-3.7.1-32.dll
inflating: 3.7.1/32bit/libgcits-3.7.1-32.pdb
inflating: 3.7.1/32bit/libssl-3.7.1-32.dll
inflating: 3.7.1/32bit/libssl-3.7.1-32.pdb
inflating: 3.7.1/32bit/vcruntime140d.dll
creating: 3.7.1/64bit/
inflating: 3.7.1/64bit/libgcirpc-3.7.1-64.dll
inflating: 3.7.1/64bit/libgcirpc-3.7.1-64.pdb
inflating: 3.7.1/64bit/libgcits-3.7.1-64.dll
inflating: 3.7.1/64bit/libgcits-3.7.1-64.pdb
inflating: 3.7.1/64bit/libssl-3.7.1-64.dll
inflating: 3.7.1/64bit/libssl-3.7.1-64.pdb
inflating: 3.7.1/64bit/vcruntime140d.dll
inflating: 3.7.1/64bit/vcruntime140_1d.dll
```
The installdir/clientLibs directory is your client libs directory. Remember this location, you will need it later.
Expand All @@ -61,7 +67,7 @@ cd <GitHub clones directory>
git clone git@github.com:GemTalk/PharoGemStoneFFI.git
```
If you have already performed the clone, do a "git pull origin development" before running the install (if you will install the current developement branch).
* Start a Pharo 9 or 10 image and open Iceberg.
* Start a Pharo 11 or 12 image and open Iceberg.
* In the Repositories window, click "+" and select "Import from existing clone".
* Select the directory you cloned to above and add the repository.
* Right click and select "Load" to load the code.
Expand Down
6 changes: 4 additions & 2 deletions src/GemStoneFFI-Tests/GciInterfaceTest.class.st
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Class {
#name : 'GciInterfaceTest',
#superclass : 'GemStoneFFITestCase',
#category : 'GemStoneFFI-Tests'
#category : 'GemStoneFFI-Tests',
#package : 'GemStoneFFI-Tests'
}

{ #category : 'tests' }
Expand All @@ -10,9 +11,10 @@ GciInterfaceTest >> testAsLocalObject [
self
assert: (GciInterface asLocalObject: GciInterface oopTrue) identicalTo: true ;
assert: (GciInterface asLocalObject: GciInterface oopFalse) identicalTo: false ;
assert: (GciInterface asLocalObject: GciInterface oopNil) identicalTo: nil ;
assert: (GciInterface oopIsSmallInt: 5330) ;
deny: (GciInterface oopIsSmallInt: 5332) ;
assert: (GciInterface asLocalObject: 5330) identicalTo: 666 ;
assert: (GciInterface asLocalObject: GciInterface OOP_CLASS_SYMBOL) identicalTo: nil .
assert: (GciInterface asLocalObject: GciInterface OOP_CLASS_SYMBOL) identicalTo: Object .
^ self
]
9 changes: 8 additions & 1 deletion src/GemStoneFFI-Tests/GemStoneFFITestCase.class.st
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ Class {
'netldi',
'stone'
],
#category : 'GemStoneFFI-Tests'
#category : 'GemStoneFFI-Tests',
#package : 'GemStoneFFI-Tests'
}

{ #category : 'acccessing' }
Expand All @@ -31,6 +32,12 @@ GemStoneFFITestCase class >> host: hostOrIp [
host := hostOrIp
]

{ #category : 'testing' }
GemStoneFFITestCase class >> isAbstract [
^ self name = GemStoneFFITestCase

]

{ #category : 'acccessing' }
GemStoneFFITestCase class >> netldi [
^netldi
Expand Down
3 changes: 2 additions & 1 deletion src/GemStoneFFI-Tests/GsExternalByteStringTest.class.st
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Class {
#name : 'GsExternalByteStringTest',
#superclass : 'GemStoneFFITestCase',
#category : 'GemStoneFFI-Tests'
#category : 'GemStoneFFI-Tests',
#package : 'GemStoneFFI-Tests'
}

{ #category : 'tests' }
Expand Down
160 changes: 159 additions & 1 deletion src/GemStoneFFI-Tests/GsSessionTest.class.st
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,15 +1,127 @@
Class {
#name : 'GsSessionTest',
#superclass : 'GemStoneFFITestCase',
#category : 'GemStoneFFI-Tests'
#category : 'GemStoneFFI-Tests',
#package : 'GemStoneFFI-Tests'
}

{ #category : 'instance creation' }
GsSessionTest class >> newLoggedInSession [

^ self newSession loginWithGsUser: 'DataCurator' password: 'swordfish' ; keepGemLog ; yourself

]

{ #category : 'instance creation' }
GsSessionTest class >> newSession [

^ GsSession newForGsVersion: self gsVersion threadSafe: true stone: self stone host: self host netldi: self netldi
]

{ #category : 'tests' }
GsSessionTest >> buildStringForSessionId: id [

"Build a string to be executed by session 2. This code will wait for up to 60 seconds for the session with the given id to exit.
It will then return the value of the shared counter, which should be 30."
| ws |
ws := WriteStream on: String new.
ws
nextPutAll: '| end delay result |' ; lf ;
nextPutAll: 'end := DateTime now addSeconds: 60.' ; lf ;
nextPutAll: 'delay := Delay forMilliseconds: 250.' ; lf ;
nextPutAll: '[System currentSessions includesIdentical: ' ; nextPutAll: id asString ; nextPutAll: ' ] whileTrue:[' ; lf ;
nextPutAll: ' DateTime now > end ifTrue:[ ^ false asString ].' ; lf ;
nextPutAll: 'delay wait.' ; lf ;
nextPutAll: '].' ; lf ;
nextPutAll: 'result := System sharedCounter: 1.' ; lf ;
nextPutAll: 'GsFile gciLogServer: (''result was '', result asString) . ' ; lf ;
nextPutAll: '^ result' .
^ ws contents


]

{ #category : 'tests' }
GsSessionTest >> doTestForkAndDetachWith: ses1 and: ses2 [

"Test fork and detach. session 1 is forked and increments a shared counter in the server 30 times, sleeping 500 ms
after each increment. session 2 waits for session 1 to exit and verifies the counter value is 30.
Test takes approx 15 seconds depending on network speed and stone loading."
| ses1id ses1str ses2str r1 r2 |
ses1str := '| delay |
System sharedCounter: 1 setValue: 0 .
delay := Delay forMilliseconds: 500.
30 timesRepeat:[
System sharedCounter: 1 incrementBy: 1 .
delay wait
].
System logout' .
ses1id := ses1 gemSessionId .
ses2str := self buildStringForSessionId: ses1id .
r1 := ses1 executeStringAndDetachNb: ses1str.
ses1 logoutNbNoError .
r2 := ses2 executeString: ses2str.
self assert: r2 equals: 30 .
^ self



]

{ #category : 'tests' }
GsSessionTest >> testForkAndDetach [
|ses1 ses2 |
self timeLimit: 1 minute. "this test takes awhile"
ses1 := self class newLoggedInSession .
ses2 := self class newLoggedInSession .
[ self doTestForkAndDetachWith: ses1 and: ses2 ]
ensure:[ ses1 logoutNbNoError. ses2 logoutNbNoError ] .
^ self

]

{ #category : 'tests' }
GsSessionTest >> testGemLogFileContents [

| s |
s := self class newLoggedInSession.
[ | tmp | self assert: (tmp := s gemLogFileNameContents) class identicalTo: ByteString ]
ensure:[ s logoutNbNoError ].
^ self

]

{ #category : 'tests' }
GsSessionTest >> testGemLogFileName [

| s |
s := self class newLoggedInSession.
[ | tmp | self assert: (tmp := s gemLogFileName) class identicalTo: ByteString ]
ensure:[ s logoutNbNoError ].
^ self

]

{ #category : 'tests' }
GsSessionTest >> testGemProcessId [

| s |
s := self class newLoggedInSession.
[ | tmp | self assert: (tmp := s gemProcessId) isInteger ] ensure:[ s logoutNbNoError ].
^ self

]

{ #category : 'tests' }
GsSessionTest >> testGemSessionId [

| s |
s := self class newLoggedInSession.
[ | tmp | self assert: (tmp := s gemSessionId) isInteger ] ensure:[ s logoutNbNoError ].
^ self

]

{ #category : 'tests' }
GsSessionTest >> testGetNbCallStatus [
|s r|
Expand Down Expand Up @@ -50,6 +162,16 @@ self assert: r equals: 'Hello, World!'.
^self
]

{ #category : 'tests' }
GsSessionTest >> testKeepGemLog [

| s |
s := self class newLoggedInSession.
[ | tmp| self assert: (tmp := s keepGemLog) ] ensure:[ s logoutNbNoError ].
^ self

]

{ #category : 'tests' }
GsSessionTest >> testLogin [

Expand All @@ -63,6 +185,42 @@ self

]

{ #category : 'tests' }
GsSessionTest >> testLoginWithSpaces [

"Test issue 5: login with leading and trailing spaces"

| stn hst nldi sess |
stn := ' ', self class stone, ' '.
host :=
hst := ' ', self class host, ' '.
nldi := ' ', self class netldi, ' '.

sess := GsSession
newForGsVersion: self class gsVersion
threadSafe: true
stone: stn
host: hst
netldi: nldi.
[ self
assert: sess class identicalTo: GsSession ;
assert: (sess loginWithGsUser: 'DataCurator' password: 'swordfish')
] ensure:[ sess ifNotNil:[ sess logoutNbNoError ] ].

^ self

]

{ #category : 'tests' }
GsSessionTest >> testLogoutError [
"test issue 12"
|sess|
sess := self class newSession .
self should:[ sess logout ] raise: Error.
^self

]

{ #category : 'tests' }
GsSessionTest >> testLogoutWhenNotLoggedIn [
|sess|
Expand Down
Empty file modified src/GemStoneFFI-Tests/package.st
100644 → 100755
Empty file.
34 changes: 0 additions & 34 deletions src/GemStoneFFI/FFICalloutAPI.extension.st

This file was deleted.

3 changes: 2 additions & 1 deletion src/GemStoneFFI/GciErrSType.class.st
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ Class {
#pools : [
'GciTypes'
],
#category : 'GemStoneFFI'
#category : 'GemStoneFFI',
#package : 'GemStoneFFI'
}

{ #category : 'ffi support' }
Expand Down
Loading

0 comments on commit 78f7581

Please sign in to comment.