Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgManifest.java @ 262:3dcd3dd90c77
Improve manifest parsing: decode bytes to chars once, minimize arraycopy on String instantiation, keep set of file revisions from previous manifest only
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 18 Aug 2011 03:46:36 +0200 |
parents | f39fb6b3cc76 |
children | 6bb5e7ed051a |
comparison
equal
deleted
inserted
replaced
261:436bb5f65ce1 | 262:3dcd3dd90c77 |
---|---|
150 } | 150 } |
151 | 151 |
152 private static class ManifestParser implements RevlogStream.Inspector { | 152 private static class ManifestParser implements RevlogStream.Inspector { |
153 private boolean gtg = true; // good to go | 153 private boolean gtg = true; // good to go |
154 private final Inspector inspector; | 154 private final Inspector inspector; |
155 private final Pool<Nodeid> nodeidPool; | 155 private Pool<Nodeid> nodeidPool; |
156 private final Pool<String> fnamePool; | 156 private final Pool<String> fnamePool; |
157 private final Pool<String> flagsPool; | 157 private final Pool<String> flagsPool; |
158 | 158 |
159 public ManifestParser(Inspector delegate) { | 159 public ManifestParser(Inspector delegate) { |
160 assert delegate != null; | 160 assert delegate != null; |
161 inspector = delegate; | 161 inspector = delegate; |
162 nodeidPool = new Pool<Nodeid>(); | 162 nodeidPool = new Pool<Nodeid>(); |
163 fnamePool = new Pool<String>(); | 163 fnamePool = new Pool<String>(); |
164 flagsPool = new Pool<String>(); | 164 flagsPool = new Pool<String>(); |
165 } | 165 } |
166 | 166 |
167 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { | 167 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { |
168 if (!gtg) { | 168 if (!gtg) { |
169 return; | 169 return; |
170 } | 170 } |
171 try { | 171 try { |
172 gtg = gtg && inspector.begin(revisionNumber, new Nodeid(nodeid, true), linkRevision); | 172 gtg = gtg && inspector.begin(revisionNumber, new Nodeid(nodeid, true), linkRevision); |
173 int i; | 173 Pool<Nodeid> thisRevPool = new Pool<Nodeid>(nodeidPool.size()); // supply hint to minimize map resize/rehash |
174 String fname = null; | 174 String fname = null; |
175 String flags = null; | 175 String flags = null; |
176 Nodeid nid = null; | 176 Nodeid nid = null; |
177 byte[] data = da.byteArray(); | 177 final char[] nodeidConvertCache = new char[40]; |
178 for (i = 0; gtg && i < actualLen; i++) { | 178 String data = new String(da.byteArray()); |
179 int x = i; | 179 final int dataLen = data.length(); // due to byte->char conversion, may be different |
180 for( ; data[i] != '\n' && i < actualLen; i++) { | 180 for (int x = 0; gtg && x < dataLen; x++) { |
181 if (fname == null && data[i] == 0) { | 181 int start = x; |
182 fname = fnamePool.unify(new String(data, x, i - x)); | 182 x = data.indexOf('\n', x+1); |
183 x = i+1; | 183 assert x != -1; |
184 int z = data.indexOf('\0', start+1); | |
185 assert z!= -1; | |
186 assert z < x; | |
187 fname = data.substring(start, z); | |
188 if (fnamePool.contains(fname)) { | |
189 fname = fnamePool.unify(fname); | |
190 } else { | |
191 fnamePool.record(fname = new String(fname)); | |
192 } | |
193 z++; // cursor at first char of nodeid | |
194 int nodeidLen = x-z < 40 ? x-z : 40; // if x-z > 40, there are flags | |
195 data.getChars(z, z+nodeidLen, nodeidConvertCache, 0); | |
196 nid = nodeidPool.unify(Nodeid.fromAscii(nodeidConvertCache, 0, nodeidLen)); | |
197 thisRevPool.record(nid); // memorize revision for the next iteration. | |
198 if (x-z > 40) { | |
199 // 'x' and 'l' for executable bits and symlinks? | |
200 // hg --debug manifest shows 644 for each regular file in my repo | |
201 // for cpython repo, there are 755 in hg --debug output when 'x' flag is present | |
202 flags = data.substring(z + nodeidLen, x); | |
203 if (flagsPool.contains(flags)) { | |
204 flags = flagsPool.unify(flags); | |
205 } else { | |
206 flagsPool.record(flags = new String(flags)); | |
184 } | 207 } |
185 } | 208 } |
186 if (i < actualLen) { | 209 gtg = gtg && inspector.next(nid, fname, flags); |
187 assert data[i] == '\n'; | |
188 int nodeidLen = i - x < 40 ? i-x : 40; | |
189 nid = nodeidPool.unify(Nodeid.fromAscii(data, x, nodeidLen)); | |
190 if (nodeidLen + x < i) { | |
191 // 'x' and 'l' for executable bits and symlinks? | |
192 // hg --debug manifest shows 644 for each regular file in my repo | |
193 flags = flagsPool.unify(new String(data, x + nodeidLen, i-x-nodeidLen)); | |
194 } | |
195 gtg = gtg && inspector.next(nid, fname, flags); | |
196 } | |
197 nid = null; | 210 nid = null; |
198 fname = flags = null; | 211 fname = flags = null; |
199 } | 212 } |
200 gtg = gtg && inspector.end(revisionNumber); | 213 gtg = gtg && inspector.end(revisionNumber); |
214 // | |
215 // keep only actual file revisions, found at this version | |
216 // (next manifest is likely to refer to most of them, although in specific cases | |
217 // like commit in another branch a lot may be useless) | |
218 nodeidPool.clear(); | |
219 nodeidPool = thisRevPool; | |
201 } catch (IOException ex) { | 220 } catch (IOException ex) { |
202 throw new HgBadStateException(ex); | 221 throw new HgBadStateException(ex); |
203 } | 222 } |
204 } | 223 } |
205 } | 224 } |