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 | |
22 | namespace 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 |
36 | HRESULT |
37 | HotTable::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 |
95 | void |
96 | HotTable::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 |