Skip to content

Commit e3606a6

Browse files
authored
Merge pull request #111 from ba-st/improvingTransactionsInRepositories
Improving transactions in repositories
2 parents 46972d7 + 4a5de0a commit e3606a6

6 files changed

+186
-48
lines changed

source/Sagan-Core-Tests/RepositoryBasedTest.class.st

+7-11
Original file line numberDiff line numberDiff line change
@@ -603,12 +603,9 @@ RepositoryBasedTest >> testUpdateInSameSessionAsFetch [
603603

604604
stallone := self silvesterStallone.
605605
self extraterrestrials
606-
transact: [ self extraterrestrials
607-
withOneMatching: [ :extraterrestrial | extraterrestrial firstName = 'John' ]
608-
do: [ :lock | self extraterrestrials update: lock with: stallone ]
609-
else: [ self fail ]
610-
].
611-
606+
withOneMatching: [ :extraterrestrial | extraterrestrial firstName = 'John' ]
607+
do: [ :lock | self extraterrestrials update: lock with: stallone ]
608+
else: [ self fail ].
612609
self assertTheOnlyOneInTheRepositoryIsSilvesterStallone
613610
]
614611

@@ -784,9 +781,8 @@ RepositoryBasedTest >> testWithOneWhereIsDoElse [
784781
RepositoryBasedTest >> updateExtraterrestrialMatching: aBlock with: aNewExtraterrestrial [
785782

786783
self extraterrestrials
787-
transact: [ self extraterrestrials
788-
withOneMatching: aBlock
789-
do: [ :extraterrestrial | self extraterrestrials update: extraterrestrial with: aNewExtraterrestrial ]
790-
else: [ self fail ]
791-
]
784+
withOneMatching: aBlock
785+
do: [ :extraterrestrial |
786+
self extraterrestrials update: extraterrestrial with: aNewExtraterrestrial ]
787+
else: [ self fail ]
792788
]

source/Sagan-Core/RepositoryBehavior.class.st

+16-10
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,11 @@ RepositoryBehavior >> matchingCriteriaBuilder [
131131
{ #category : 'management' }
132132
RepositoryBehavior >> purge: aDomainObject [
133133

134-
^ self
135-
assertIncludes: aDomainObject;
136-
purgeAfterCheckingInclusion: aDomainObject
134+
^ self transact: [
135+
self
136+
assertIncludes: aDomainObject;
137+
purgeAfterCheckingInclusion: aDomainObject
138+
]
137139
]
138140

139141
{ #category : 'private - management' }
@@ -151,9 +153,11 @@ RepositoryBehavior >> purgeAllMatching: aCriteria [
151153
{ #category : 'management' }
152154
RepositoryBehavior >> store: aDomainObject [
153155

154-
^ self
155-
assertNoConflictsFor: aDomainObject;
156-
storeAfterCheckingConflicts: aDomainObject
156+
^ self transact: [
157+
self
158+
assertNoConflictsFor: aDomainObject;
159+
storeAfterCheckingConflicts: aDomainObject
160+
]
157161
]
158162

159163
{ #category : 'private - management' }
@@ -177,10 +181,12 @@ RepositoryBehavior >> update: aDomainObject executing: aBlock [
177181
{ #category : 'management' }
178182
RepositoryBehavior >> update: aDomainObject with: anUpdatedDomainObject [
179183

180-
^ self
181-
assertIncludes: aDomainObject;
182-
assertNoConflictsFor: anUpdatedDomainObject excluding: aDomainObject;
183-
updateAfterCheckingConflicts: aDomainObject with: anUpdatedDomainObject
184+
^ self transact: [
185+
self
186+
assertIncludes: aDomainObject;
187+
assertNoConflictsFor: anUpdatedDomainObject excluding: aDomainObject;
188+
updateAfterCheckingConflicts: aDomainObject with: anUpdatedDomainObject
189+
]
184190
]
185191

186192
{ #category : 'private - management' }

source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st

+57-13
Original file line numberDiff line numberDiff line change
@@ -19,36 +19,46 @@ GemStoneRepositoryProviderTest >> pickTwoElementsFrom: aQuery [
1919
]
2020

2121
{ #category : 'initialization' }
22-
GemStoneRepositoryProviderTest >> setUpRepositoryWith: aConflictCheckingStrategy [
22+
GemStoneRepositoryProviderTest >> setUpRepositoryProvidedBy: aGemStoneRepositoryProvider with: aConflictCheckingStrategy [
2323

24-
extraterrestrials := GemStoneRepositoryProvider new
24+
extraterrestrials := aGemStoneRepositoryProvider
2525
createRepositoryStoringObjectsOfType: Extraterrestrial
2626
checkingConflictsAccordingTo: aConflictCheckingStrategy.
2727
extraterrestrials configureWith: [ :repository |
28-
repository
29-
indexByEquality: 'firstName' typed: String;
30-
indexByEquality: 'lastName' typed: String
28+
repository
29+
indexByEquality: 'firstName' typed: String;
30+
indexByEquality: 'lastName' typed: String
3131
].
3232
ships := GemStoneRepositoryProvider new
3333
createRepositoryStoringObjectsOfType: Spaceship
3434
checkingConflictsAccordingTo: aConflictCheckingStrategy
3535
]
3636

37+
{ #category : 'initialization' }
38+
GemStoneRepositoryProviderTest >> setUpRepositoryWith: aConflictCheckingStrategy [
39+
40+
self setUpRepositoryProvidedBy: GemStoneRepositoryProvider new with: aConflictCheckingStrategy
41+
]
42+
43+
{ #category : 'initialization' }
44+
GemStoneRepositoryProviderTest >> setUpSemaphorizedRepositoryWaitingOn: aSemaphore [
45+
46+
self
47+
setUpRepositoryProvidedBy: ( SemaphorizedGemStoneRepositoryProvider waitingOn: aSemaphore )
48+
with: DoNotCheckForConflictsStrategy new
49+
]
50+
3751
{ #category : 'tests' }
3852
GemStoneRepositoryProviderTest >> testExceptionsAbortTransactionsUntilHandled [
3953

4054
self assert: self extraterrestrials findAll isEmpty.
41-
42-
self extraterrestrials transact: [
43-
[
55+
[
4456
self extraterrestrials store: self silvesterStallone.
4557
self assertTheOnlyOneInTheRepositoryIsSilvesterStallone.
4658
1 / 0
47-
]
48-
on: ZeroDivide
49-
do: [ :ex | ex return ]
50-
].
51-
59+
]
60+
on: ZeroDivide
61+
do: [ :ex | ex return ].
5262
self assertTheOnlyOneInTheRepositoryIsSilvesterStallone
5363
]
5464

@@ -500,6 +510,40 @@ GemStoneRepositoryProviderTest >> testTransactionLevelWithUnhandledException [
500510
self assert: System transactionLevel equals: baseLevel
501511
]
502512

513+
{ #category : 'tests' }
514+
GemStoneRepositoryProviderTest >> testUpdateWithWhileAbbortTransactionsAreSignaled [
515+
516+
| stallone semaphore previous |
517+
518+
previous := System transactionMode.
519+
[
520+
System transactionMode: #manualBegin.
521+
semaphore := Semaphore new.
522+
self setUpSemaphorizedRepositoryWaitingOn: semaphore.
523+
stallone := self silvesterStallone.
524+
self extraterrestrials store: stallone.
525+
self
526+
assert: self extraterrestrials findAll size equals: 1;
527+
assert: ( self extraterrestrials findAll includes: stallone ).
528+
[
529+
self
530+
updateExtraterrestrialMatching: [ :extraterrestrial | extraterrestrial firstName = 'Silvester' ]
531+
with: self johnLock
532+
] fork.
533+
Processor yield.
534+
System inTransaction ifFalse: [ System abortTransaction ].
535+
semaphore signal.
536+
Processor yield.
537+
self assert: self extraterrestrials findAll size equals: 1.
538+
self extraterrestrials
539+
withOneMatching: [ :extraterrestrial | extraterrestrial firstName = 'John' ]
540+
do: [ :john | self assert: john lastName equals: 'Lock' ]
541+
else: [ self fail ].
542+
self assert: ( self extraterrestrials findAllMatching: [ :extraterrestrial |
543+
extraterrestrial lastName = 'Stallone' ] ) isEmpty
544+
] ensure: [ System transactionMode: previous ]
545+
]
546+
503547
{ #category : 'utility' }
504548
GemStoneRepositoryProviderTest >> withAllSpaceshipsMatching: aMatchingCriteria do: aOneArgBlock [
505549

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"
2+
This class is specifically created for testing transaction management in crud services of repostiories
3+
"
4+
Class {
5+
#name : 'SemaphorizedGemStoneRepository',
6+
#superclass : 'GemStoneRepository',
7+
#instVars : [
8+
'semaphore'
9+
],
10+
#category : 'Sagan-GemStone-Tests',
11+
#package : 'Sagan-GemStone-Tests'
12+
}
13+
14+
{ #category : 'instance creation' }
15+
SemaphorizedGemStoneRepository class >> checkingConflictsAccordingTo: aConflictCheckingStrategy waitingOn: aSemaphore [
16+
17+
^ self new initializeCheckingConflictsAccordingTo: aConflictCheckingStrategy waitingOn: aSemaphore
18+
]
19+
20+
{ #category : 'initialization' }
21+
SemaphorizedGemStoneRepository >> initializeCheckingConflictsAccordingTo: aConflictCheckingStrategy waitingOn: aSemaphore [
22+
23+
self initializeCheckingConflictsAccordingTo: aConflictCheckingStrategy.
24+
semaphore := aSemaphore
25+
]
26+
27+
{ #category : 'private - management' }
28+
SemaphorizedGemStoneRepository >> synchronize: aDomainObject with: anUpdatedDomainObject [
29+
30+
super synchronize: aDomainObject with: anUpdatedDomainObject.
31+
semaphore wait
32+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"
2+
This class is specifically created for testing transaction management in crud services of repostiories
3+
"
4+
Class {
5+
#name : 'SemaphorizedGemStoneRepositoryProvider',
6+
#superclass : 'RepositoryProvider',
7+
#instVars : [
8+
'semaphore'
9+
],
10+
#category : 'Sagan-GemStone-Tests',
11+
#package : 'Sagan-GemStone-Tests'
12+
}
13+
14+
{ #category : 'instance creation' }
15+
SemaphorizedGemStoneRepositoryProvider class >> waitingOn: aSemaphore [
16+
17+
^ self new initializeWaitingOn: aSemaphore
18+
]
19+
20+
{ #category : 'building' }
21+
SemaphorizedGemStoneRepositoryProvider >> createRepositoryStoringObjectsOfType: aBusinessObjectClass
22+
checkingConflictsAccordingTo: aConflictCheckingStrategy [
23+
24+
25+
^ SemaphorizedGemStoneRepository
26+
checkingConflictsAccordingTo: aConflictCheckingStrategy
27+
waitingOn: semaphore
28+
]
29+
30+
{ #category : 'controlling' }
31+
SemaphorizedGemStoneRepositoryProvider >> destroyRepositories [
32+
33+
IndexManager current removeAllIndexes
34+
]
35+
36+
{ #category : 'initialization' }
37+
SemaphorizedGemStoneRepositoryProvider >> initializeWaitingOn: aSemaphore [
38+
39+
semaphore := aSemaphore
40+
]
41+
42+
{ #category : 'controlling' }
43+
SemaphorizedGemStoneRepositoryProvider >> prepareForInitialPersistence [
44+
45+
46+
]
47+
48+
{ #category : 'controlling' }
49+
SemaphorizedGemStoneRepositoryProvider >> prepareForShutDown [
50+
51+
52+
]
53+
54+
{ #category : 'initialization' }
55+
SemaphorizedGemStoneRepositoryProvider >> reset [
56+
57+
58+
]

source/Sagan-GemStone/GemStoneRepository.class.st

+16-14
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,12 @@ GemStoneRepository >> matchingCriteriaBuilder [
127127
{ #category : 'private - management' }
128128
GemStoneRepository >> purgeAfterCheckingInclusion: aDomainObject [
129129

130-
^ self transact: [
131-
contents remove: aDomainObject ifAbsent: [
132-
DataInconsistencyFound signal:
133-
( '<1p> was expected to be found in the contents, but it was not.' expandMacrosWith:
134-
aDomainObject )
135-
].
136-
aDomainObject
137-
]
130+
contents remove: aDomainObject ifAbsent: [
131+
DataInconsistencyFound signal:
132+
( '<1p> was expected to be found in the contents, but it was not.' expandMacrosWith:
133+
aDomainObject )
134+
].
135+
^ aDomainObject
138136
]
139137

140138
{ #category : 'management' }
@@ -153,10 +151,14 @@ GemStoneRepository >> saganGemStoneIndexOptions [
153151
{ #category : 'private - management' }
154152
GemStoneRepository >> storeAfterCheckingConflicts: aDomainObject [
155153

156-
^ self transact: [
157-
contents add: aDomainObject.
158-
aDomainObject
159-
]
154+
contents add: aDomainObject.
155+
^ aDomainObject
156+
]
157+
158+
{ #category : 'private - management' }
159+
GemStoneRepository >> synchronize: aDomainObject with: anUpdatedDomainObject [
160+
161+
aDomainObject synchronizeWith: anUpdatedDomainObject
160162
]
161163

162164
{ #category : 'management' }
@@ -175,8 +177,8 @@ GemStoneRepository >> update: aMutableDomainObject executing: aBlock [
175177
GemStoneRepository >> updateAfterCheckingConflicts: aDomainObject with: anUpdatedDomainObject [
176178

177179
self purgeAfterCheckingInclusion: aDomainObject.
178-
[ aDomainObject synchronizeWith: anUpdatedDomainObject ] ensure: [
179-
self storeAfterCheckingConflicts: aDomainObject ].
180+
[ self synchronize: aDomainObject with: anUpdatedDomainObject ] ensure: [
181+
self storeAfterCheckingConflicts: aDomainObject ].
180182
^ aDomainObject
181183
]
182184

0 commit comments

Comments
 (0)