//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 2000. // // File: MCURSOR.CXX // // Contents: Merge Cursor // // Classes: CMergeCursor // // History: 06-May-91 BartoszM Created // // widHeap keyHeap // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include "mcursor.hxx" //+--------------------------------------------------------------------------- // // Member: CMergeCursor::CMergeCursor, public // // Synopsis: Create a cursor that merges a number of cursors. // // Arguments: [cCursor] -- count of cursors // [aCursor] -- array of pointers to cursors // // History: 06-May-91 BartoszM Created // 24-Jan-92 AmyA Modified to take CKeyCurArray as a // parameter. // // Notes: The cursors and the array will be deleted by destructor. // Leaves widHeap empty. // //---------------------------------------------------------------------------- CMergeCursor::CMergeCursor( CKeyCurStack & stkCursor ) : _keyHeap (), _widHeap ( stkCursor.Count() ) { _widMax = 0; // not valid // Two step construction of the heap. // We have to make sure that all cursors have a valid key int cCursor = stkCursor.Count(); int count = 0; // remove empty cursors. GetKey() can fail; don't leak cursors. for ( int i = 0; i < cCursor; i++ ) { CKeyCursor *pCur = stkCursor.Get( i ); Win4Assert( 0 != pCur ); if ( 0 == pCur->GetKey() ) stkCursor.Free( i ); else count++; } XArray aCursor( count ); for ( count = 0, i = 0; i < cCursor; i++ ) { CKeyCursor *pCur = stkCursor.Get( i ); if ( 0 != pCur ) aCursor[ count++ ] = pCur; } delete [] stkCursor.AcqStack(); _keyHeap.MakeHeap ( count, aCursor.Acquire() ); if ( !_keyHeap.IsEmpty() ) { _iid = _keyHeap.Top()->IndexId(); _pid = _keyHeap.Top()->Pid(); } ciDebugOut(( DEB_ITRACE, "merge cursor has %d cursors\n", count )); } //CMergeCursor //+--------------------------------------------------------------------------- // // Member: CMergeCursor::GetKey, public // // Synopsis: Get current key. // // History: 06-May-91 BartoszM Created // // Notes: Does not replenish widHeap // Current key is defined as: // 1. cur key of all cursors in widHeap, or, // 2. if widHeap empty, cur key of Top of key heap // (and cur key of all cursors in keyHeap with // the same cur key). // //---------------------------------------------------------------------------- const CKeyBuf * CMergeCursor::GetKey() { if ( _widHeap.IsEmpty() ) { if ( _keyHeap.IsEmpty() ) return 0; return _keyHeap.Top()->GetKey(); } return _widHeap.Top()->GetKey(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::WorkId, public // // Synopsis: Get current work id. // // History: 06-May-91 BartoszM Created // // Notes: Current wid is defined as: // 1. Cur wid of Top of widHeap (and cur wid of all // cursors in widHeap with the same wid-- however, // NextWid should not increment the others, since // they correspond to different index id's), or, // 2. if widHeap empty: replenish it // //---------------------------------------------------------------------------- WORKID CMergeCursor::WorkId() { if ( _widHeap.IsEmpty() && !ReplenishWid() ) return widInvalid; return _widHeap.Top()->WorkId(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::Occurrence, public // // Synopsis: Get current occurrence. // // History: 06-May-91 BartoszM Created // // Notes: Current occurrence is defined as: // 1. cur occ of Top of widHeap, or, // 2. if widHeap empty, replenish it. // //---------------------------------------------------------------------------- OCCURRENCE CMergeCursor::Occurrence() { if ( _widHeap.IsEmpty() && !ReplenishWid() ) return OCC_INVALID; return _widHeap.Top()->Occurrence(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::GetNextKey, public // // Synopsis: Move to next key // // Returns: Target key or NULL if no more keys // // History: 06-May-91 BartoszM Created // // Effects: Updates _iid _pid to the ones of the keyHeap top // // Notes: 1. Increment and move to keyHeap all cursors // from widHeap, or, // 2. if widHeap empty, increment and reheap all // cursors in keyHeap with the same cur key // as the Top. // //---------------------------------------------------------------------------- const CKeyBuf * CMergeCursor::GetNextKey() { if ( ! _widHeap.IsEmpty() ) { // move widHeap to keyHeap advancing all cursors CKeyCursor * cur; while ( ( cur = _widHeap.RemoveBottom() ) != 0 ) { if ( cur->GetNextKey() == 0 ) { delete cur; } else { _keyHeap.Add ( cur ); } } } else if ( !_keyHeap.IsEmpty() ) { // widHeap was empty. Advance all cursors // with the lowest key. CKeyBuf key = *_keyHeap.Top()->GetKey(); do { if ( _keyHeap.Top()->GetNextKey() == 0 ) { delete _keyHeap.RemoveTop(); if ( _keyHeap.IsEmpty () ) return 0; } else { _keyHeap.Reheap(); } } while ( AreEqual(&key, _keyHeap.Top()->GetKey()) ); } else return 0; if ( _keyHeap.IsEmpty() ) return 0; CKeyCursor* cur = _keyHeap.Top(); _pid = cur->Pid(); _iid = cur->IndexId(); return cur->GetKey(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::NextWorkId, public // // Synopsis: Move to next work id // // Returns: Target work id or widInvalid if no more wid's for current key // // Effects: Updates _iid to the one of the widHeap top // // // History: 06-May-91 BartoszM Created // // Notes: The same work id may be returned multiple times, // corresponding to multiple indexes. // 1. Increment Top of widHeap and reheap, or, // 2. if widHeap empty, replenish it // //---------------------------------------------------------------------------- WORKID CMergeCursor::NextWorkId() { if ( _widHeap.IsEmpty() && !ReplenishWid() ) return widInvalid; _widHeap.Top()->NextWorkId(); _widHeap.Reheap(); CKeyCursor* cur = _widHeap.Top(); _iid = cur->IndexId(); return cur->WorkId(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::NextOccurrence, public // // Synopsis: Move to next occurrence // // Returns: Target occurrence or OCC_INVALID if no more occurrences // for current (wid, index id) combination. // // History: 06-May-91 BartoszM Created // // Notes: 1. Increment Top of widHeap (do not reheap!), or, // 2. if widHeap empty, replenish it // //---------------------------------------------------------------------------- OCCURRENCE CMergeCursor::NextOccurrence() { if ( _widHeap.IsEmpty() && !ReplenishWid() ) return OCC_INVALID; return _widHeap.Top()->NextOccurrence(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::MaxOccurrence // // Synopsis: Returns max occurrence of current wid // // History: 20-Jun-96 SitaramR Created // //---------------------------------------------------------------------------- OCCURRENCE CMergeCursor::MaxOccurrence() { if ( _widHeap.IsEmpty() ) return OCC_INVALID; return _widHeap.Top()->MaxOccurrence(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::WorkIdCount, public // // Synopsis: return wid count // // History: 21-Jun-91 BartoszM Created // // Notes: 1. Sum up wid count of all cursors in widHeap, or, // 2. if widHeap empty, replenish it // //---------------------------------------------------------------------------- ULONG CMergeCursor::WorkIdCount() { // Sum up all wid counts for the same key. // move all cursors with the same key to wid heap if (_widHeap.IsEmpty() && !ReplenishWid()) { return 0; } int count = _widHeap.Count(); ULONG widCount = 0; CKeyCursor **curVec = _widHeap.GetVector(); while ( --count >= 0 ) widCount += curVec[count]->WorkIdCount(); // ciDebugOut (( DEB_ITRACE, "merge : wid count %ld\n", widCount )); return widCount; } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::OccurrenceCount, public // // Synopsis: return occurrence count // // History: 21-Jun-91 BartoszM Created // // Notes: 1. Return occ count of Top of widHeap // Occ counts of other cursors with the // same wid do not count! They will // be returned after NextWorkId is called // 2. if widHeap empty, replenish it // //---------------------------------------------------------------------------- ULONG CMergeCursor::OccurrenceCount() { if ( _widHeap.IsEmpty() && !ReplenishWid() ) { return 0; } return _widHeap.Top()->OccurrenceCount(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::HitCount, public // // Synopsis: return occurrence count // // History: 27-Feb-92 AmyA Created // // Notes: see notes for OccurrenceCount(). // //---------------------------------------------------------------------------- ULONG CMergeCursor::HitCount() { return OccurrenceCount(); } //+--------------------------------------------------------------------------- // // Member: CMergeCursor::ReplenishWid, protected // // Synopsis: Replenish the wid heap // // Returns: TRUE if successful, FALSE if key heap exhausted // // Effects: Updates _iid to the ones of the widHeap top // // History: 06-May-91 BartoszM Created // //---------------------------------------------------------------------------- BOOL CMergeCursor::ReplenishWid() { if ( _keyHeap.IsEmpty() ) { return FALSE; } // Move all cursors with the lowest key // to widHeap CKeyBuf key = *(_keyHeap.Top()->GetKey()); do { CKeyCursor* cur = _keyHeap.RemoveTop(); _widHeap.Add ( cur ); } while ( !_keyHeap.IsEmpty() && AreEqual( &key, _keyHeap.Top()->GetKey()) ); _iid = _widHeap.Top()->IndexId(); return TRUE; } // // Remove RefillStream() and FreeStream() once NTFS supports // sparse file operations on parts of a file when other parts // of the file are mapped. This won't happen any time soon. // void CMergeCursor::FreeStream() { ULONG cCursors = _keyHeap.Count(); CKeyCursor **aCursors = _keyHeap.GetVector(); ciDebugOut(( DEB_ITRACE, "free key heap has %d cursors\n", cCursors )); for ( ULONG i = 0; i < cCursors; i++ ) aCursors[ i ]->FreeStream(); cCursors = _widHeap.Count(); aCursors = _widHeap.GetVector(); ciDebugOut(( DEB_ITRACE, "free wid heap has %d cursors\n", cCursors )); for ( i = 0; i < cCursors; i++ ) aCursors[ i ]->FreeStream(); } //FreeStream void CMergeCursor::RefillStream() { ULONG cCursors = _keyHeap.Count(); CKeyCursor **aCursors = _keyHeap.GetVector(); ciDebugOut(( DEB_ITRACE, "refill key heap has %d cursors\n", cCursors )); for ( ULONG i = 0; i < cCursors; i++ ) aCursors[ i ]->RefillStream(); cCursors = _widHeap.Count(); aCursors = _widHeap.GetVector(); ciDebugOut(( DEB_ITRACE, "refill wid heap has %d cursors\n", cCursors )); for ( i = 0; i < cCursors; i++ ) aCursors[ i ]->RefillStream(); } //FreeStream