OSDN Git Service

Fix TortoiseGitBlame miss GitLogCache problem.
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / GitLogCache.cpp
1 #include "stdafx.h"\r
2 #include "GitLogCache.h"\r
3 \r
4 CLogCache::CLogCache()\r
5 {\r
6 \r
7 }\r
8 \r
9 CLogCache::~CLogCache()\r
10 {\r
11         //this->m_IndexFile.Close();\r
12         //this->m_DataFile.Close();\r
13 }\r
14 int CLogCache::AddCacheEntry(GitRev &Rev)\r
15 {\r
16         this->m_NewCacheEntry.push_back(Rev);\r
17         return 0;\r
18 }\r
19 \r
20 int CLogCache::GetCacheData(GitRev &Rev)\r
21 {\r
22         if(this->m_HashMapIndex.find(Rev.m_CommitHash)==m_HashMapIndex.end())\r
23         {\r
24                 for(int i=0;i<this->m_NewCacheEntry.size();i++)\r
25                 {\r
26                         if(m_NewCacheEntry[i].m_CommitHash==Rev.m_CommitHash)\r
27                         {\r
28                                 Rev.CopyFrom(m_NewCacheEntry[i],true);\r
29                                 return 0;\r
30                         }\r
31                 }\r
32                 return -1;\r
33         }\r
34         else\r
35         {\r
36                 return LoadOneItem(Rev,m_HashMapIndex[Rev.m_CommitHash]);\r
37         }\r
38         return 0;\r
39 }\r
40 int CLogCache::FetchCacheIndex(CString GitDir)\r
41 {\r
42 \r
43         if(this->m_IndexFile.m_hFile == CFile::hFileNull)\r
44         {\r
45                 BOOL b=m_IndexFile.Open(GitDir+_T("\\.git\\")+INDEX_FILE_NAME,\r
46                         CFile::modeRead|CFile::shareDenyNone|\r
47                         CFile::modeNoTruncate|CFile::modeCreate);\r
48                 if(!b)\r
49                         return -1;\r
50         }\r
51         //Cache has been fetched.\r
52         //if(m_GitDir == GitDir)\r
53         //      return 0;\r
54 \r
55         m_GitDir=GitDir;\r
56         m_IndexFile.SeekToBegin();\r
57 \r
58         SLogCacheIndexHeader header;\r
59         UINT count=m_IndexFile.Read(&header,sizeof(SLogCacheIndexHeader));\r
60         if(count != sizeof(SLogCacheIndexHeader))\r
61                 return -2;\r
62 \r
63         if( header.m_Magic != LOG_INDEX_MAGIC )\r
64                 return -3;\r
65 \r
66         if( header.m_Version != LOG_INDEX_VERSION )\r
67                 return -4;\r
68 \r
69 \r
70         SLogCacheItem Item;\r
71 \r
72         //for(int i=0;i<header.m_ItemCount;i++)\r
73         this->m_HashMapIndex.clear();\r
74 \r
75         while(1)\r
76         {\r
77                 count=m_IndexFile.Read(&Item,sizeof(SLogCacheItem));    \r
78                 if( count != sizeof(SLogCacheItem) )\r
79                         break;\r
80 \r
81                 CString str;\r
82                 g_Git.StringAppend(&str,Item.m_Hash,CP_UTF8,40);\r
83                 this->m_HashMapIndex[str]=Item.m_Offset;\r
84         }\r
85 \r
86         return 0;\r
87 }\r
88 \r
89 int CLogCache::SaveOneItem(GitRev &Rev,ULONGLONG offset)\r
90 {\r
91         \r
92         SLogCacheRevItemHeader header;\r
93         m_DataFile.Seek(offset,CFile::begin);\r
94 \r
95         if(this->m_DataFile.m_hFile == CFile::hFileNull)\r
96         {\r
97                 BOOL b=m_DataFile.Open(m_GitDir+_T("\\.git\\")+INDEX_FILE_NAME,\r
98                         CFile::modeRead|CFile::shareDenyNone|\r
99                         CFile::modeNoTruncate|CFile::modeCreate);\r
100                 if(!b)\r
101                         return -1;\r
102         }\r
103 \r
104         header.m_Magic=LOG_DATA_ITEM_MAGIC;\r
105         header.m_Version=LOG_INDEX_VERSION;\r
106         header.m_FileCount=Rev.m_Files.GetCount();\r
107 \r
108         m_DataFile.Write(&header,sizeof(SLogCacheRevItemHeader));\r
109         \r
110         CArchive ar(&m_DataFile, CArchive::store);\r
111 \r
112         ar<<Rev.m_AuthorName;\r
113         ar<<Rev.m_AuthorEmail;\r
114         ar<<Rev.m_AuthorDate;\r
115         ar<<Rev.m_CommitterName;\r
116         ar<<Rev.m_CommitterEmail;\r
117         ar<<Rev.m_CommitterDate;\r
118         ar<<Rev.m_Subject;\r
119         ar<<Rev.m_Body;\r
120         ar<<Rev.m_CommitHash;\r
121         ar<<Rev.m_Action;\r
122 \r
123         for(int i=0;i<Rev.m_Files.GetCount();i++)\r
124         {\r
125                 SLogCacheRevFileHeader header;\r
126                 header.m_Magic=LOG_DATA_FILE_MAGIC;\r
127                 header.m_Version=LOG_INDEX_VERSION;\r
128 \r
129                 ar<<header.m_Magic;\r
130                 ar<<header.m_Version;\r
131                 ar<<Rev.m_Files[i].GetGitPathString();\r
132                 ar<<Rev.m_Files[i].m_Action;\r
133                 ar<<Rev.m_Files[i].m_Stage;\r
134                 ar<<Rev.m_Files[i].m_StatAdd;\r
135                 ar<<Rev.m_Files[i].m_StatDel;\r
136                 \r
137         }\r
138         return 0;\r
139 }\r
140 \r
141 int CLogCache::LoadOneItem(GitRev &Rev,ULONGLONG offset)\r
142 {\r
143         SLogCacheRevItemHeader header;\r
144 \r
145         if(this->m_DataFile.m_hFile == CFile::hFileNull)\r
146         {\r
147                 BOOL b=m_DataFile.Open(m_GitDir+_T("\\.git\\")+DATA_FILE_NAME,\r
148                         CFile::modeRead|CFile::shareDenyNone|\r
149                         CFile::modeNoTruncate|CFile::modeCreate);\r
150                 if(!b)\r
151                         return -1;\r
152         }\r
153         m_DataFile.Seek(offset,CFile::begin);\r
154 \r
155         UINT count=m_DataFile.Read(&header,sizeof(SLogCacheRevItemHeader));\r
156         if( count != sizeof(SLogCacheRevItemHeader))\r
157                 return -1;\r
158         if( !CheckHeader(header))\r
159                 return -2;\r
160 \r
161 \r
162         CArchive ar(&m_DataFile, CArchive::load);\r
163 \r
164         ar>>Rev.m_AuthorName;\r
165         ar>>Rev.m_AuthorEmail;\r
166         ar>>Rev.m_AuthorDate;\r
167         ar>>Rev.m_CommitterName;\r
168         ar>>Rev.m_CommitterEmail;\r
169         ar>>Rev.m_CommitterDate;\r
170         ar>>Rev.m_Subject;\r
171         ar>>Rev.m_Body;\r
172         ar>>Rev.m_CommitHash;\r
173         ar>>Rev.m_Action;\r
174 \r
175         Rev.m_Files.Clear();\r
176 \r
177         for(int i=0;i<header.m_FileCount;i++)\r
178         {\r
179                 CTGitPath path;\r
180                 CString file;\r
181                 path.Reset();\r
182                 SLogCacheRevFileHeader header;\r
183 \r
184                 ar>>header.m_Magic;\r
185                 ar>>header.m_Version;\r
186 \r
187                 if( this->CheckHeader(header) )\r
188                         return -1;\r
189                 ar>>file;\r
190                 path.SetFromGit(file);\r
191 \r
192                 ar>>path.m_Action;\r
193                 ar>>path.m_Stage;\r
194                 ar>>path.m_StatAdd;\r
195                 ar>>path.m_StatDel;\r
196                 \r
197                 \r
198                 Rev.m_Files.AddPath(path);\r
199         }\r
200         return 0;\r
201 }\r
202 int CLogCache::RebuildCacheFile()\r
203 {\r
204         m_IndexFile.SetLength(0);\r
205         m_DataFile.SetLength(0);\r
206         {\r
207                 SLogCacheIndexHeader header;\r
208                 header.m_Magic=LOG_INDEX_MAGIC;\r
209                 header.m_Version=LOG_INDEX_VERSION;\r
210                 m_IndexFile.SeekToBegin();\r
211                 m_IndexFile.Write(&header,sizeof(SLogCacheIndexHeader));\r
212         }\r
213         \r
214         {\r
215                 SLogCacheRevFileHeader header;\r
216                 header.m_Magic=LOG_DATA_MAGIC;\r
217                 header.m_Version=LOG_INDEX_VERSION;\r
218 \r
219                 m_DataFile.SeekToBegin();\r
220                 m_DataFile.Write(&header,sizeof(SLogCacheRevFileHeader));\r
221         }\r
222         return 0;\r
223 }\r
224 int CLogCache::SaveCache()\r
225 {\r
226         if( this->m_NewCacheEntry.size() == 0 )\r
227                 return 0;\r
228 \r
229         bool bIsRebuild=false;\r
230         if(this->m_DataFile.m_hFile != CFile::hFileNull)\r
231                 m_DataFile.Close();\r
232         if(this->m_IndexFile.m_hFile!=CFile::hFileNull)\r
233                 m_IndexFile.Close();\r
234 \r
235         if(this->m_IndexFile.m_hFile == CFile::hFileNull)\r
236         {\r
237                 BOOL b=m_IndexFile.Open(m_GitDir+_T("\\.git\\")+INDEX_FILE_NAME,\r
238                         CFile::modeReadWrite|CFile::shareDenyWrite|\r
239                         CFile::modeNoTruncate|CFile::modeCreate);\r
240                 if(!b)\r
241                         return -1;\r
242         }\r
243 \r
244         if(this->m_DataFile.m_hFile == CFile::hFileNull)\r
245         {\r
246                 BOOL b=m_DataFile.Open(m_GitDir+_T("\\.git\\")+DATA_FILE_NAME,\r
247                         CFile::modeReadWrite|CFile::shareDenyWrite|\r
248                         CFile::modeNoTruncate|CFile::modeCreate);\r
249 \r
250                 \r
251                 if(!b)\r
252                 {\r
253                         m_IndexFile.Close();\r
254                         return -1;\r
255                 }\r
256         }\r
257 \r
258         {\r
259                 SLogCacheIndexHeader header;\r
260                 memset(&header,0,sizeof(SLogCacheIndexHeader));\r
261                 UINT count=m_IndexFile.Read(&header,sizeof(SLogCacheIndexHeader));\r
262                 if(count != sizeof(SLogCacheIndexHeader) || !this->CheckHeader(header))\r
263                 {// new file\r
264                         RebuildCacheFile();\r
265                         bIsRebuild=true;\r
266                 }\r
267         }\r
268 \r
269         {\r
270 \r
271                 SLogCacheRevFileHeader header;\r
272         \r
273                 UINT count=m_DataFile.Read(&header,sizeof(SLogCacheRevFileHeader));\r
274                 if( count != sizeof(SLogCacheRevFileHeader) || !CheckHeader(header))\r
275                 {\r
276                         RebuildCacheFile();\r
277                         bIsRebuild=true;\r
278                 }\r
279         \r
280         }\r
281 \r
282         m_DataFile.SeekToEnd();\r
283         m_IndexFile.SeekToEnd();\r
284         for(int i=0;i<this->m_NewCacheEntry.size();i++)\r
285         {\r
286                 if(this->m_HashMapIndex.find(m_NewCacheEntry[i].m_CommitHash) == m_HashMapIndex.end() || bIsRebuild)\r
287                 {\r
288                         ULONGLONG offset = m_DataFile.GetPosition();\r
289                         this->SaveOneItem(m_NewCacheEntry[i],offset);\r
290 \r
291                         SLogCacheItem item;\r
292                         for(int j=0; j<40;j++)\r
293                                 item.m_Hash[j]=(BYTE)m_NewCacheEntry[i].m_CommitHash[j];\r
294                         item.m_Offset=offset;\r
295 \r
296                         m_IndexFile.Write(&item,sizeof(SLogCacheItem));\r
297                 }\r
298         }\r
299         m_IndexFile.Close();\r
300         m_DataFile.Close();\r
301         return 0;\r
302 }