Bug: 33963

Impact:

Product:
GemEnterprise

Versions:
2.0, 1.1, 1.0

Platform:
All

Fixed In:

Problems with replication of subclasses of RcIdentityBag

There is a bug in the replication logic for subclasses of RcIdentityBag
that causes object corruption during replication.  This bug *only* applies
in the following cases:

1.  The number of public named instance variables in the class definition
    for the subclass of RcIdentityBag differs between the two servers.

2.  The ordering of public named instance variables is different.

3.  GsfReplicationSpecs are used to modify the mapping between public
    named instance variables between the two servers.

Note that this bug *DOES NOT* apply when using subclasses of RcIdentityBag
that are the same across servers.

The corruption takes one of these forms:

1.  Objects which were elements in the RcIdentityBag end up as values in
    one of the public named instance variables.

2.  Objects which were in one of the public named instance variables end

    up as elements in the RcIdentityBag.

3.  Objects shift from one public named instance variable to another.

Workaround:

Make sure that all servers in the Federation uses the same definition for
subclasses of RcIdentityBag, using the same named instance variables in
the same order.  Also, do not use replication specs to modify instance
variable mapping between servers.

If you *must* support different subclass definitions and/or replication
specs on RcIdentityBag subclasses, you can file-in the following code as
instructed:

1.  Login a topaz session as SystemUser.
2.  File-in the following code and commit:

!----------------------------------------------------------------------------
!
! Fix for GemEnterprise bug 33963 effecting
! replication of subclasses of RcIdentityBags
!
category: 'Federation - Private'
method: RcIdentityBag
_fedTraversalCallback

"Return the contents of the receiver."

| arr subcomp count |

" must write each subcomponent to get conflict with concurrent adder/remover
" 1 to: components size do: [ :i |
  (subcomp := components at: i) ~~ nil
    ifTrue: [ subcomp _putInWriteSet ]
].
" write the component array to get conflict " components size: components
size.

arr := Array new. self _addAllTo: arr.

" put public named inst vars on the end (an optimization when unpacking)
" count := 0. self class _replicateFirstPublicInstVar to: self class instSize
do: [ :i |
  arr add: (self instVarAt: i).
  count := count + 1.
].

" fix 33963: last element in arr is the number of public named inst vars
" arr add: count.

GemStoneFederation _sessionState ignoredObjects add: arr.
^ arr
%
category: 'Federation - Private'
method: RcIdentityBag
_updateVaryingFrom: buffer

"Update the varying portion of the receiver from the given traversal buffer.
The traversal callback should put an identity bag in the value buffer."

| localObj remoteOop namedSize varyingSize numPrivate index repSpec ivMap
|

buffer numberOfValueBuffOops ~~ 1
  ifTrue: [ self _halt: 'RcIdentityBag > _updateVaryingFrom: wrong value
buffer' ].

remoteOop := buffer valueBufferRemoteOop. localObj := buffer localObjectForValueBufferOop:
buffer remoteObjectSpace
  otherwise: _remoteNil. buffer advanceValueBufferOop.

localObj == _remoteNil
  ifTrue: [ " forward reference "
    ^ buffer addForwardReference: self ivOffset: -1 remoteOop: remoteOop
  ].

numPrivate := self class _replicateFirstPublicInstVar - 1. namedSize :=
self class instSize - self class _replicateFirstPublicInstVar + 1.

" fix 33963: add replication spec support " ( ( repSpec := buffer remoteObjectSpace
replicationSpecForLocalClass: self class ) == nil )
  ifTrue: [ ivMap := nil ]
  ifFalse: [ ivMap := repSpec _getInstVarMap ].

" fix 33963: modify varyingSize calculation to use last item in localObj
" varyingSize := ( localObj size ) - ( localObj at: ( localObj size ) )
- 1.

1 to: namedSize do: [ :i |

  " fix 33963: modify replication logic to use replication specs "
  ( ivMap isNil )
    ifTrue: [ self _replicateInstVarAt: numPrivate + i put: (localObj at:
varyingSize + i) ]
    ifFalse: [ self _replicateInstVarAt: numPrivate + i put:
        (localObj at:  ( varyingSize + (ivMap at: numPrivate + i) - numPrivate
)) ].
].
localObj size: varyingSize.

self addAll: localObj. buffer remoteObjectSpace _unreplicate: localObj
remoteOop: remoteOop.
%
!
!----------------------------------------------------------------------------