tikhomirov@600: /* tikhomirov@600: * Copyright (c) 2013 TMate Software Ltd tikhomirov@600: * tikhomirov@600: * This program is free software; you can redistribute it and/or modify tikhomirov@600: * it under the terms of the GNU General Public License as published by tikhomirov@600: * the Free Software Foundation; version 2 of the License. tikhomirov@600: * tikhomirov@600: * This program is distributed in the hope that it will be useful, tikhomirov@600: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@600: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@600: * GNU General Public License for more details. tikhomirov@600: * tikhomirov@600: * For information on how to redistribute this software under tikhomirov@600: * the terms of a license other than GNU General Public License tikhomirov@600: * contact TMate Software at support@hg4j.com tikhomirov@600: */ tikhomirov@600: package org.tmatesoft.hg.internal; tikhomirov@600: tikhomirov@600: import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; tikhomirov@600: tikhomirov@600: import java.util.Arrays; tikhomirov@600: tikhomirov@600: import org.tmatesoft.hg.core.Nodeid; tikhomirov@628: import org.tmatesoft.hg.repo.HgInvalidControlFileException; tikhomirov@628: import org.tmatesoft.hg.repo.HgInvalidRevisionException; tikhomirov@600: import org.tmatesoft.hg.repo.HgRevisionMap; tikhomirov@628: import org.tmatesoft.hg.repo.HgRuntimeException; tikhomirov@600: tikhomirov@600: /** tikhomirov@600: * Lite alternative to {@link HgRevisionMap}, to speed up nodeid to index conversion without consuming too much memory. tikhomirov@600: * E.g. for a 100k revisions, {@link HgRevisionMap} consumes 3 * (N * sizeof(int)) for indexes plus 48 bytes per tikhomirov@600: * Nodeid instance, total (12+48)*N = 6 mb of memory. {RevisionLookup} instead keeps only Nodeid hashes, (N * sizeof(int) = 400 kb), tikhomirov@600: * but is slower in lookup, O(N/2) to find potential match plus disk read operatin (or few, in an unlikely case of hash collisions). tikhomirov@600: * tikhomirov@600: * @author Artem Tikhomirov tikhomirov@600: * @author TMate Software Ltd. tikhomirov@600: */ tikhomirov@600: public class RevisionLookup implements RevlogStream.Inspector { tikhomirov@600: tikhomirov@600: private final RevlogStream content; tikhomirov@600: private int[] nodeidHashes; tikhomirov@600: tikhomirov@600: public RevisionLookup(RevlogStream stream) { tikhomirov@600: assert stream != null; tikhomirov@600: content = stream; tikhomirov@600: } tikhomirov@600: tikhomirov@628: public static RevisionLookup createFor(RevlogStream stream) throws HgRuntimeException { tikhomirov@600: RevisionLookup rv = new RevisionLookup(stream); tikhomirov@600: int revCount = stream.revisionCount(); tikhomirov@600: rv.prepare(revCount); tikhomirov@600: if (revCount > 0) { tikhomirov@600: stream.iterate(0, revCount - 1, false, rv); tikhomirov@600: } tikhomirov@600: return rv; tikhomirov@600: } tikhomirov@600: tikhomirov@600: public void prepare(int count) { tikhomirov@600: nodeidHashes = new int[count]; tikhomirov@600: Arrays.fill(nodeidHashes, BAD_REVISION); tikhomirov@600: } tikhomirov@600: public void next(int index, byte[] nodeid) { tikhomirov@600: nodeidHashes[index] = Nodeid.hashCode(nodeid); tikhomirov@600: } tikhomirov@600: public void next(int index, Nodeid nodeid) { tikhomirov@600: nodeidHashes[index] = nodeid.hashCode(); tikhomirov@600: } tikhomirov@628: public int findIndex(Nodeid nodeid) throws HgInvalidControlFileException, HgInvalidRevisionException { tikhomirov@600: final int hash = nodeid.hashCode(); tikhomirov@600: for (int i = 0; i < nodeidHashes.length; i++) { tikhomirov@600: if (nodeidHashes[i] == hash) { tikhomirov@600: byte[] nodeidAtI = content.nodeid(i); tikhomirov@600: if (nodeid.equalsTo(nodeidAtI)) { tikhomirov@600: return i; tikhomirov@600: } tikhomirov@600: } tikhomirov@600: // else: false match (only 4 head bytes matched, continue loop tikhomirov@600: } tikhomirov@600: return BAD_REVISION; tikhomirov@600: } tikhomirov@600: tikhomirov@600: public void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { tikhomirov@600: next(revisionIndex, nodeid); tikhomirov@600: } tikhomirov@600: }