1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5// File: HotTable.cpp
6//
7
8//
9// Class code:MetaData::HotTable stores hot table records cache, a cache of often-accessed
10// table records stored only in NGEN images.
11// The cache is created using IBC logging.
12//
13// ======================================================================================
14
15#include "external.h"
16
17#include "hottable.h"
18#include "hotdataformat.h"
19
20#include <metamodelpub.h>
21
22namespace MetaData
23{
24
25// --------------------------------------------------------------------------------------
26//
27// Returns S_OK if index (nIndex) is present in the hot table record cache and returns its value from
28// cache (*ppRecord).
29// Returns S_FALSE if offset is not in the hot table record cache, DOES NOT initialize *ppRecord in this
30// case!
31// Returns error code otherwise (and sets *pRecord to NULL).
32//
33
34//static
35__checkReturn
36HRESULT
37HotTable::GetData(
38 UINT32 nRowIndex,
39 __deref_out_opt BYTE **ppRecord,
40 UINT32 cbRecordSize,
41 struct HotTableHeader *pHotTableHeader)
42{
43 BYTE *pHotTableHeaderData = (BYTE *)pHotTableHeader;
44
45 if (pHotTableHeader->m_nFirstLevelTable_PositiveOffset != 0)
46 { // Has first level table
47 // fetch the first level table
48 WORD *pFirstLevelTable = (WORD *)(pHotTableHeaderData + pHotTableHeader->m_nFirstLevelTable_PositiveOffset);
49
50 // find the high order bits of the rid
51 BYTE bRid = (BYTE)(nRowIndex >> pHotTableHeader->m_shiftCount);
52
53 // use the low order bits of the rid to index into
54 // the first level table.
55 UINT32 nMask = (1 << pHotTableHeader->m_shiftCount) - 1;
56 int i = pFirstLevelTable[nRowIndex & nMask];
57 int end = pFirstLevelTable[(nRowIndex & nMask) + 1];
58
59 // the generation logic should make sure either all tables are present
60 // or all absent.
61 _ASSERTE(pHotTableHeader->m_nSecondLevelTable_PositiveOffset != 0);
62 _ASSERTE(pHotTableHeader->m_offsIndexMappingTable != 0);
63
64 // fetch second level and index mapping tables
65 BYTE *pSecondLevelTable = pHotTableHeaderData + pHotTableHeader->m_nSecondLevelTable_PositiveOffset;
66 WORD *pIndexMappingTable = (WORD *)(pHotTableHeaderData + pHotTableHeader->m_offsIndexMappingTable);
67
68 // look for the high order bits of the rid in the second level table.
69 // search is linear, but should be short on average.
70 for ( ; i < end; i++)
71 {
72 if (pSecondLevelTable[i] == bRid)
73 {
74 // we have found the hot rid we are looking for
75
76 // now consult the index mapping table to find where the hot data is stored
77 int index = pIndexMappingTable[i];
78
79 *ppRecord = pHotTableHeaderData + pHotTableHeader->m_offsHotData + (index * cbRecordSize);
80 return S_OK;
81 }
82 }
83 // Not found in hot data
84 return S_FALSE;
85 }
86 // no first level table - this implies the whole table is replicated
87 // in the hot section. simply multiply and fetch the right record.
88 // hot indices are 0-based, rids are 1-base, so need to subtract 1 from rid.
89
90 *ppRecord = pHotTableHeaderData + pHotTableHeader->m_offsHotData + ((nRowIndex - 1) * cbRecordSize);
91 return S_OK;
92} // HotTable::GetData
93
94// static
95void
96HotTable::CheckTables(struct HotTablesDirectory *pHotTablesDirectory)
97{
98#ifdef _DEBUG
99 _ASSERTE(pHotTablesDirectory->m_nMagic == HotTablesDirectory::const_nMagic);
100
101 for (UINT32 nTableIndex = 0; nTableIndex < TBL_COUNT; nTableIndex++)
102 {
103 if (pHotTablesDirectory->m_rgTableHeader_SignedOffset[nTableIndex] != 0)
104 {
105 struct HotTableHeader *pHotTableHeader = GetTableHeader(pHotTablesDirectory, nTableIndex);
106
107 _ASSERTE((pHotTableHeader->m_cTableRecordCount > 0) && (pHotTableHeader->m_cTableRecordCount <= USHRT_MAX));
108 if (pHotTableHeader->m_nFirstLevelTable_PositiveOffset == 0)
109 {
110 _ASSERTE(pHotTableHeader->m_nSecondLevelTable_PositiveOffset == 0);
111 _ASSERTE(pHotTableHeader->m_offsIndexMappingTable == 0);
112 _ASSERTE(pHotTableHeader->m_offsHotData == Align4(sizeof(struct HotTableHeader)));
113 }
114 else
115 {
116 UINT32 nFirstLevelTableOffset = sizeof(struct HotTableHeader);
117 _ASSERTE(pHotTableHeader->m_nFirstLevelTable_PositiveOffset == nFirstLevelTableOffset);
118 UINT32 cbFirstLevelTableSize = sizeof(WORD) * ((1 << pHotTableHeader->m_shiftCount) + 1);
119
120 _ASSERTE(pHotTableHeader->m_nSecondLevelTable_PositiveOffset != 0);
121 UINT32 nSecondLevelTableOffset = nFirstLevelTableOffset + cbFirstLevelTableSize;
122 _ASSERTE(pHotTableHeader->m_nSecondLevelTable_PositiveOffset == nSecondLevelTableOffset);
123 UINT32 cbSecondLevelTableSize = sizeof(BYTE) * pHotTableHeader->m_cTableRecordCount;
124
125 _ASSERTE(pHotTableHeader->m_offsIndexMappingTable != 0);
126 UINT32 nIndexMappingTableOffset = nSecondLevelTableOffset + cbSecondLevelTableSize;
127 _ASSERTE(pHotTableHeader->m_offsIndexMappingTable == nIndexMappingTableOffset);
128 UINT32 cbIndexMappingTableSize = sizeof(WORD) * pHotTableHeader->m_cTableRecordCount;
129
130 UINT32 nHotDataOffset = nIndexMappingTableOffset + cbIndexMappingTableSize;
131 _ASSERTE(pHotTableHeader->m_offsHotData == Align4(nHotDataOffset));
132 }
133 }
134 }
135#endif //_DEBUG
136} // HotTable::CheckTables
137
138}; // namespace MetaData
139