!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: rcidxbktcache.gs,v 1.8 2008-01-09 22:50:13 stever Exp $
!
! Superclass Hierarchy:
!   RcIndexBucketWithCache, RcIndexBucket, RcCollisionBucket,
!   CollisionBucket, Array, SequenceableCollection, Collection, Object.
!
! class created in idxclasses.topaz
!=========================================================================

removeallmethods RcIndexBucketWithCache
removeallclassmethods RcIndexBucketWithCache

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

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

txt := (GsDocText new) details:
'An RcIndexBucketWithCache is an RcIndexBucket that is used by the indexing
 subsystem where appropriate to improve indexing performance.' .
doc documentClassWith: txt.

self description: doc.
%

! ------------------- Instance methods for RcIndexBucketWithCache

category: 'Constants'
method: RcIndexBucketWithCache
_numCacheSlots

"Returns the number of initial slots reserved for cached values."

"NOTE: This constant is dependent upon corresponding with
 RCINDEXBUCKET_NUM_CACHE_SLOTS defined in index.ht."

^ 23
%

category: 'Accessing'
method: RcIndexBucketWithCache
valueOffsetFor: index

"Returns the value at the specified index."

^ "self entrySize" 3 * index + "self _numCacheSlots" 23
%

category: 'Updating'
method: RcIndexBucketWithCache
insertedBucketValueBagAt: offset

"Updates the cache with the fact that a BucketValueBag was inserted at the given
 offset."

<primitive: 216>
self _primitiveFailed: #insertedBucketValueBagAt: .
self _uncontinuableError

%

category: 'Updating'
method: RcIndexBucketWithCache
removedBucketValueBagAt: offset

"Updates the cache with the fact that a BucketValueBag was removed at the given
 offset."

<primitive: 217>
self _primitiveFailed: #removedBucketValueBagAt: .
self _uncontinuableError
%

category: 'Testing'
method: RcIndexBucketWithCache
_isBucketValueBagAt: offset

"Returns whether the object at the given offset in the receiver is a
 BucketValueBag.  Use the cache to determine this without fetching the
 object at the offset."

<primitive: 187>
self _primitiveFailed: #_isBucketValueBagAt: .
self _uncontinuableError
%

category: 'Updating'
method: RcIndexBucketWithCache
at: anIndex putKey: aKey

"Stores the key aKey into the key part of the key/value/pathTerm triplet
 referenced by atIndex."

self
  _basicAt: (anIndex * "self entrySize" 3) + "self _numCacheSlots - 2" 21
  put: aKey
%

category: 'Updating'
method: RcIndexBucketWithCache
at: anIndex putTerm: pathTerm

"Stores the pathTerm into the pathTerm part of the key/value/pathTerm triplet
 referenced by atIndex."

self
  _basicAt: (anIndex * "self entrySize" 3) + "self _numCacheSlots - 1" 22
  put: pathTerm
%

category: 'Updating'
method: RcIndexBucketWithCache
at: anIndex putValue: aValue

"Stores the value aValue into the value part of the key/value/pathTerm triplet
 referenced by atIndex."

self _basicAt: (self valueOffsetFor: anIndex) put: aValue
%

category: 'Accessing'
method: RcIndexBucketWithCache
keyAt: index

"Returns the key at the specified index."

^ self _rcAt: ("self entrySize" 3 * index) + "self _numCacheSlots - 2" 21
%

category: 'Accessing'
method: RcIndexBucketWithCache
termAt: index

"Returns the term at the specified index."

^ self _rcAt: ("self entrySize" 3 * index) + "self _numCacheSlots - 1" 22
%

category: 'Accessing'
method: RcIndexBucketWithCache
valueAt: index

"Returns the value at the specified index."

^ self _rcAt: ( "self entrySize" 3 * index + "self _numCacheSlots" 23 )
%

category: 'Accessing'
method: RcIndexBucketWithCache
firstAt: aKey term: pathTerm otherwise: aValue
 
"Returns the value that corresponds aKey/pathTerm by searching the elements in
 the bucket.  If no such key/value/pathTerm triplet exists, returns aValue.
 If the value is a BucketValueBag, returns the first object in the Bag
 that is not identical to aKey."
 
| val index |
index := self searchForKey: aKey term: pathTerm.
index == nil
  ifTrue: [ ^ aValue ].
 
val := self valueAt: index.
(self _isBucketValueBagAt: (self valueOffsetFor: index))
  ifTrue: [
    1 to: val size do: [ :i |
      (val _at: i) ~~ aKey
        ifTrue: [ ^ val _at: i ]
    ].
    ^ aValue
  ]
  ifFalse: [ ^ val ]
%

category: 'Updating'
method: RcIndexBucketWithCache
insertedEntryAt: offset

"Updates the cache with the fact that an entry was inserted at the given
 offset."

self _shiftCacheAt: offset forAddition: true
%

category: 'Updating'
method: RcIndexBucketWithCache
removedEntryAt: offset

"Updates the cache with the fact that an entry was removed at the given offset."

self _shiftCacheAt: offset forAddition: false
%

category: 'Updating'
method: RcIndexBucketWithCache
_shiftCacheAt: offset forAddition: aBoolean

"Invokes the primitive that shifts cache bits appropriately."

<primitive: 218>

self _primitiveFailed: #_shiftCacheAt:forAddition: .
self _uncontinuableError
%

category: 'Updating'
method: RcIndexBucketWithCache
_refreshBucketCacheReportingInto: aString

"Verifies that the cache contains correct entries.  If the cache contains an
 incorrect entry, fix it.  Appends a description of any problems found onto the
 given string."

1 to: numElements do: [ :i | | val valOffset |
  val := self valueAt: i.
  valOffset := self valueOffsetFor: i.
  ( BucketValueBag _hasInstance: val )
    ifTrue: [
      ( self _isBucketValueBagAt: valOffset )
        ifFalse: [ " cache says no when it should say yes "
          self insertedBucketValueBagAt: valOffset.
          aString add: ' updated cache entry at: ';
            add: valOffset asString;
            add: ' to indicate a BucketValueBag';
            add: Character lf.
        ]
    ]
    ifFalse: [
      ( self _isBucketValueBagAt: valOffset )
        ifTrue: [ " cache says yes when it should say no "
          self removedBucketValueBagAt: valOffset.
          aString add: ' updated cache entry at: '; 
            add: valOffset asString;
            add: ' to indicate no BucketValueBag';
            add: Character lf.
        ]
    ]
].
^ aString
%
