!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: rcrangeindex.gs,v 1.4 2008-01-09 22:50:14 stever Exp $
!
! Superclass Hierarchy:
!   RcRangeEqualityIndex, RangeEqualityIndex, IdentityIndex, Array, SequenceableCollection,
!   Collection, Object.
!
! class created in idxclasses.topaz
!=========================================================================

removeallmethods RcRangeEqualityIndex
removeallclassmethods RcRangeEqualityIndex

category: 'For Documentation Installation only'
classmethod: RcRangeEqualityIndex
installDocumentation

| doc txt |
doc := GsClassDocumentation _newForPrivateGsClass: self.

txt := (GsDocText new) details:
''.

doc documentClassWith: txt.

self description: doc.
%

! ------------------- Class methods for RcRangeEqualityIndex
category: 'Instance Creation'
classmethod: RcRangeEqualityIndex
newWithLastElementClass: aClass

"Create a new instance and initialize its B-tree root."

| newOne |
newOne := super new.
newOne lastElementClass: aClass.
newOne btreeRoot: aClass rcBtreeLeafNodeClass new.
^ newOne
%
! ------------------- Instance methods for RcRangeEqualityIndex
category: 'Updating'
method: RcRangeEqualityIndex
btreeAt: aKey put: aValue

"Insert the key/value pair into the root B-tree node.  Must check to see if a
 split occurred.  If so, create a new root node and put the old root and the
 new split node into the new root."

(self _canCompareWith: aKey)
    ifFalse: [
      ^ self _error: #rtErrRangeEqualityIndexInvalidClassKindForBtree
        args: #[ aKey, lastElementClass ]
    ].

self _btreeAt: aKey put: aValue logging: true
%
category: 'Updating'
method: RcRangeEqualityIndex
btreeRemoveKey: aKey value: aValue

"Removes the key and value from the B-tree root node.  Must check to see if
 a merge occurred in the root such that the root only contains a single
 entry.  If so, make the single entry the new root.  Returns whether the
 removal occurred."

^ self _btreeRemoveKey: aKey value: aValue logging: true
%
category: 'Updating'
method: RcRangeEqualityIndex
_btreeAt: aKey put: aValue logging: aBoolean

"Insert the key/value pair into the root B-tree node.  Must check to see if a
 split occurred.  If so, create a new root node and put the old root and the
 new split node into the new root."

| returnNode node |
returnNode := btreeRoot btreeAt: aKey put: aValue for: self logging: aBoolean.

" see if a split occurred "
returnNode == btreeRoot
    ifFalse: [ " returnNode is the second half of the split "
        " create the new parent node "
        node := btreeRoot parentNodeClass new.
        node lastValue: returnNode lastValue.

        " insert the first half (the original root) "
        node
            _insertKey: (btreeRoot _at: btreeRoot _lastKeyIndex)
            value: btreeRoot
            atIndex: 1.
        " insert the second half "
        node
            _insertKey: (returnNode _at: returnNode _lastKeyIndex)
            value: returnNode
            atIndex: (node entrySize + 1).

        System _addRootObjectToRcReadSet: node.
        System redoLog addConflictObject: node for: self.

        btreeRoot := node.
    ].
System _addRootObjectToRcReadSet: btreeRoot.
System _addRootObjectToRcReadSet: self.
System redoLog addConflictObject: btreeRoot for: self.
aBoolean 
  ifTrue: [ 
    self _logBtreeAt: aKey put: aValue. 
  ].
^true
%
category: 'Updating'
method: RcRangeEqualityIndex
_btreeRemoveKey: aKey value: aValue logging: aBoolean

"Removes the key and value from the B-tree root node.  Must check to see if
 a merge occurred in the root such that the root only contains a single
 entry.  If so, make the single entry the new root.  Returns whether the
 removal occurred."

(btreeRoot removeKey: aKey value: aValue for: self logging: aBoolean)
    ifTrue: [
        ((btreeRoot numElements == 1) _and: [ btreeRoot isLeaf not ] )
            ifTrue: [ btreeRoot := btreeRoot at: (btreeRoot _lastKeyIndex - 1) ].
        System redoLog addConflictObject: btreeRoot for: self.
        aBoolean 
          ifTrue: [ 
            self _logBtreeRemoveKey: aKey value: aValue.
          ].
        ^ true
    ]
    ifFalse: [ ^ false ].
%
category: 'Private'
method: RcRangeEqualityIndex
_logBtreeAt: aKey put: aValue

"Create a log entry for adding the given key/value."

| logEntry |
logEntry := LogEntry new.
logEntry receiver: self;
    selector: #_btreeAt:put:logging:;
    argArray: #[ aKey, aValue, false ].
System redoLog addLogEntry: logEntry
%
category: 'Private'
method: RcRangeEqualityIndex
_logBtreeRemoveKey: aKey value: aValue

"Create a log entry for removing the given key/value."

| logEntry |
logEntry := LogEntry new.
logEntry receiver: self;
    selector: #_btreeRemoveKey:value:logging:;
    argArray: #[ aKey, aValue, false ].
System redoLog addLogEntry: logEntry
%
category: 'Private'
method: RcRangeEqualityIndex
_resolveRcConflictsWith: conflictObjects

"A logical write-write conflict has occurred on the receiver.  The objects that
 had the actual physical write-write conflicts are in the conflictObjects
 Array.  Selectively abort the receiver and then attempt to replay the
 operations maintained in the System redo log.  Returns true if all the
 operations could be replayed; otherwise returns false."

"inline implementation of _abortAndReplay: to abort old btrees before
 replaying log entries."

| redoLog logEntries |
redoLog := System _redoLog.
    
" if no log entries to replay, then we're done "
redoLog == nil ifTrue: [ ^ false ].
logEntries := redoLog getLogEntriesFor: self .
logEntries == nil ifTrue:[ ^ false ].
   
" cannot perform selective abort if receiver has a dependency tag "
self _hasDependencyList ifTrue: [ ^ false ].

" explicitly abort the btrees that made up original changes, since we need to abort entire tree, before replaying, since
  nodes may split differently."
1 to: conflictObjects size do:[ :j |
  (conflictObjects at: j) _selectiveAbort 
].
    
"abort all of the btree nodes involved in the transaction"
redoLog conflictObjects keysAndValuesDo:[ :conflictObject :redoObject |
  redoObject == self ifTrue: [ conflictObject _selectiveAbort ].
].

" refresh the state of the receiver "
self _selectiveAbort.
    
" tell the redo log to replay any operations on the receiver "
^ redoLog _redoOperationsForEntries: logEntries 
%
