view src/org/tmatesoft/hg/internal/RevlogCompressor.java @ 593:9619301a7bb9

Share last revision read between #iterate() invocations, to save revision rebuild efforts when few subsequent revisions are read
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 02 May 2013 16:51:02 +0200
parents 243202f1bda5
children 7c0d2ce340b8
line wrap: on
line source
/*
 * Copyright (c) 2013 TMate Software Ltd
 *  
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * For information on how to redistribute this software under
 * the terms of a license other than GNU General Public License
 * contact TMate Software at support@hg4j.com
 */
package org.tmatesoft.hg.internal;

import java.io.IOException;
import java.util.zip.Deflater;

import org.tmatesoft.hg.core.SessionContext;
import org.tmatesoft.hg.util.LogFacility.Severity;

/**
 * 
 * @author Artem Tikhomirov
 * @author TMate Software Ltd.
 */
public class RevlogCompressor {
	private final SessionContext ctx;
	private final Deflater zip;
	private DataSerializer.DataSource sourceData;
	private int compressedLen;
	
	public RevlogCompressor(SessionContext sessionCtx) {
		ctx = sessionCtx;
		zip = new Deflater();
	}

	public void reset(DataSerializer.DataSource source) {
		sourceData = source;
		compressedLen = -1;
	}
	
	// out stream is not closed!
	public int writeCompressedData(DataSerializer out) throws IOException {
		zip.reset();
		DeflaterDataSerializer dds = new DeflaterDataSerializer(out, zip, sourceData.serializeLength());
		sourceData.serialize(dds);
		dds.finish();
		return zip.getTotalOut();
	}

	public int getCompressedLength() {
		if (compressedLen != -1) {
			return compressedLen;
		}
		Counter counter = new Counter();
		try {
			compressedLen = writeCompressedData(counter);
			assert counter.totalWritten == compressedLen;
	        return compressedLen;
		} catch (IOException ex) {
			// can't happen provided we write to our stream that does nothing but byte counting
			ctx.getLog().dump(getClass(), Severity.Error, ex, "Failed estimating compressed length of revlog data");
			return counter.totalWritten; // use best known value so far
		}
	}

	private static class Counter extends DataSerializer {
		public int totalWritten = 0;

		public void writeByte(byte... values) throws IOException {
			totalWritten += values.length;
		}

		public void writeInt(int... values) throws IOException {
			totalWritten += 4 * values.length;
		}

		public void write(byte[] data, int offset, int length) throws IOException {
			totalWritten += length;
		}
	}
}