!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: unorderedcoll2.gs,v 1.17 2008-01-09 22:50:20 stever Exp $
!
! Superclass Hierarchy:
!   UnorderedCollection, Collection, Object.
!
!========================================================================

category: 'Indexing Support'
method: UnorderedCollection
_getIndexReferencesInto: refsToRcvr

"Returns an Array of information about references to the receiver due to the
 receiver's participation in an index as a set-valued instance variable.
 The Array consists of pairs:

 1) An object that references the receiver.
 2) The offset of the instance variable in that object that references the
  receiver.

 This is used only in support of the 'become:' method; therefore if
 the receiver is a root NSC with an index, an error will be raised."

| indexList pathTerm index vals obj pathTerms |
indexList := self _indexedPaths.
pathTerms := IdentitySet new.
" for each index that the receiver participates in ... "
2 to: indexList size by: 2 do: [ :i |
  " check if it is the root NSC or a set-valued instance variable "
  (indexList at: i) == 1
    ifTrue: [ " it is the root, 'become:' not allowed "
      self _error: #rtErrCantBecomeIndexedNsc.
    ]
    ifFalse: [
      (indexList at: i) > 1
        ifTrue: [
          index := indexList at: i - 1.
          pathTerm := index at: (indexList at: i) - 2.
          " only want to check each unique path term "
          (pathTerms includesIdentical: pathTerm)
            ifFalse: [
              " get the objects that refer to the receiver "
              vals := index indexDictionary at: self term: pathTerm otherwise: nil.
              nil == vals
                ifTrue: [
                  index indexDictionary _errorNoEntryForKey: self
                    term: pathTerm
                    value: nil
                ].

              (BucketValueBag _hasInstance: vals)
                ifTrue: [
                  1 to: vals size do: [ :j |
                    obj := vals _at: j.
                    self _addToReferences: obj
                      offset: (pathTerm _ivOffsetFor: obj)
                      occurrences: 1
                      into: refsToRcvr
                  ]
                ]
                ifFalse: [
                  self _addToReferences: vals
                    offset: (pathTerm _ivOffsetFor: vals)
                    occurrences: 1
                    into: refsToRcvr
                ].
                pathTerms add: pathTerm
              ]
        ]
    ]
].
" since NSCs may have named instance variables, invoke this on super "
^ super _getIndexReferencesInto: refsToRcvr
%

! deleted UnorderedCollection>>_explicitEqualityIndexedPaths v2.0

! deleted UnorderedCollection>>_explicitIdentityIndexedPaths v2.0

! deleted UnorderedCollection>>_explicitEqualityIndexedPathsAndConstraints v2.0

! deleted UnorderedCollection>>_deadNscBeingGarbageCollected v2.0

category: 'Clustering'
method: UnorderedCollection
_clusterIndexes

"Clusters indexing objects.  This may cause concurrency conflicts on
 internal indexing objects.  Returns the receiver."

| iList |
(iList := self _indexedPaths) == nil
  ifTrue: [ 
    ^ self 
  ].

" cluster the index dictionary "
self _indexDictionary ~~ nil
  ifTrue: [ self _indexDictionary clusterDepthFirst ].

" cluster each index object "
1 to: iList size by: 2 do: [ :j |
  (iList at: j) _isIndexObject
    ifTrue: [ (iList at: j) clusterDepthFirst ]
].
%

category: 'Indexing Support'
method: UnorderedCollection
_indexStatistics

"Return a dictionary containing statistics that can be useful in determining the
 performance of indexes.  This information is useful for system administrators
 and customer support in determining how to optimize index usage."

| dict |
dict := SymbolDictionary new.
self _indexedPaths == nil
  ifTrue: [
    dict at: #NoIndexesPresent put: true.
    ^ dict
  ].

self _indexedPaths _statisticsInto: dict.
self _indexDictionary ~~ nil
  ifTrue: [ self _indexDictionary _statisticsInto: dict ].

^ dict
%

category: 'Indexing Support'
method: UnorderedCollection
_refreshIndexCaches

"This method is currently unsupported, but is provided for customer support.

 Verifies that the index dictionary bucket caches are correct.  If an invalid
 entry is found, fixes it and reports where the fix occurred."

| result |
self _indexDictionary ~~ nil
  ifTrue: [ result := self _indexDictionary _refreshBucketCaches ].
( result == nil _or: [ result isEmpty ] )
  ifTrue: [ result := 'No problems found with index caches' ].
^ result
%


category: 'Indexing Support'
method: UnorderedCollection
_setIndexDictionaryWorkingSetInterval: aNumber

"Sets the working set interval for the index dictionary when index creation
 is in progress.  This will only be in effect for the life of the transaction."

aNumber _validateClass: Number.
System
  rcValueCacheAt: #indexDictionaryWorkingSetInterval
  put: aNumber
  for: self.
^ aNumber
%

category: 'Indexing Audit'
method: UnorderedCollection
_auditAndRepairDepListsLogging: aString

"Get any dependency lists we can find and repair them if they need it.
Report any repairs on the given string."

| depLists sharedDepLists depList cnt |
sharedDepLists := SharedDependencyLists.
depLists := self _getAllDependencyLists.
cnt := 0.
1 to: depLists size do: [ :i |
  (depList := depLists at: i) _needsSorting
    ifTrue: [
      cnt := cnt + 1.
      depList _sortEntries: (sharedDepLists depListBucketFor: depList).
    ]
].
cnt > 0
  ifTrue: [
    aString add: 'For nsc ['; add: self identityHash asString;
      add: '] repaired '; add: cnt asString; add: ' dependency list(s)';
      add: Character lf.
  ].
^ aString
%

category: 'Indexing Audit'
method: UnorderedCollection
_getAllDependencyLists

"Return a set of all dependency lists that we can find from the receiver."

| all iList rootTerms obj sz prevObj bag |

all := IdentitySet new.
iList := self _indexedPaths.
bag := self _asIdentityBag.
iList ~~ nil
  ifTrue: [
    prevObj := #_incompletePathTraversal.
    rootTerms := iList rootTerms.
    sz := rootTerms size.
    1 to: bag size do: [ :i |
      obj := bag _at: i.
      obj == prevObj
        ifFalse: [
          1 to: sz do: [ :j |
            (rootTerms at: j) allDependencyListsFor: obj into: all
          ]
        ].
      prevObj := obj
    ]
  ].
^ all
%

