Package org.xtreemfs.babudb.log

Source Code of org.xtreemfs.babudb.log.LogEntry

/*
* Copyright (c) 2008 - 2011, Jan Stender, Bjoern Kolbeck, Mikael Hoegqvist,
*                     Felix Hupfeld, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/

package org.xtreemfs.babudb.log;

import java.util.zip.Checksum;

import org.xtreemfs.babudb.lsmdb.LSN;
import org.xtreemfs.babudb.lsmdb.LSMDBRequest;
import org.xtreemfs.foundation.buffer.BufferPool;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;

/**
*
* @author bjko
*/
public class LogEntry {
   
    /**
     * length of the entry's header (excluding the length field itself)
     */
    protected static final int  headerLength        = Integer.SIZE / 8 * 4 +
                                                  Long.SIZE / 8 + Byte.SIZE / 8;
   
    public static final boolean USE_CHECKSUMS       = true;
   
    public static final byte    PAYLOAD_TYPE_INSERT = 0;
   
    public static final byte    PAYLOAD_TYPE_SNAP   = 1;
   
    public static final byte    PAYLOAD_TYPE_CREATE = 2;
   
    public static final byte    PAYLOAD_TYPE_COPY   = 3;
   
    public static final byte    PAYLOAD_TYPE_DELETE = 4;
       
    public static final byte    PAYLOAD_TYPE_SNAP_DELETE = 5;
   
    public static final byte    PAYLOAD_TYPE_TRANSACTION = 6;
   
    /**
     * view ID of the log entry. The view ID is an epoch number which creates a
     * total order on the log entries (viewId.logSequenceNo).
     */
    protected int               viewId              = -1;
   
    protected long              logSequenceNo       = -1L;
   
    protected int               checksum;
   
    protected ReusableBuffer    payload;
   
    protected SyncListener      listener;
   
    private LSMDBRequest<?>     attachment;
   
    protected byte              payloadType;
   
    private LogEntry() {
    }
       
    public LogEntry(ReusableBuffer payload, SyncListener l, byte payloadType) {
        assert(payload != null);
       
        this.payload = payload;
        this.listener = l;
        this.payloadType = payloadType;
    }
   
    public void assignId(int viewId, long logSequenceNo) {
        this.viewId = viewId;
        this.logSequenceNo = logSequenceNo;
    }
   
    public ReusableBuffer serialize(Checksum csumAlgo) {
        assert (viewId > 0);
        assert (logSequenceNo > 0);
       
        final int bufSize = headerLength + payload.remaining();
        ReusableBuffer buf = BufferPool.allocate(bufSize);
        buf.putInt(bufSize);
        buf.putInt(checksum);
        buf.putInt(viewId);
        buf.putLong(logSequenceNo);
        buf.put(payloadType);
        buf.put(payload);
        payload.flip(); // otherwise payload is not reusable
        buf.putInt(bufSize);
        buf.flip();
       
        if (USE_CHECKSUMS) {
            // reset the old checksum to 0, before calculating a new one
            buf.position(Integer.SIZE / 8);
            buf.putInt(0);
            buf.position(0);
           
            csumAlgo.update(buf.array(), 0, buf.limit());
            int cPos = buf.position();
           
            // write the checksum to the buffer
            buf.position(Integer.SIZE / 8);
            buf.putInt((int) csumAlgo.getValue());
            buf.position(cPos);
        }
       
        return buf;
    }
   
    public void setListener(SyncListener listener) {
        this.listener = listener;
    }
   
    public SyncListener getListener() {
        return listener;
    }
   
    public ReusableBuffer getPayload() {
        return this.payload;
    }
   
    public int getViewId() {
        return this.viewId;
    }
   
    public long getLogSequenceNo() {
        return this.logSequenceNo;
    }
   
    public LSN getLSN() {
        if (this.viewId == -1 && this.logSequenceNo == -1L) return null;
        else return new LSN(this.viewId, this.logSequenceNo);
    }
   
    public static void checkIntegrity(ReusableBuffer data)
        throws LogEntryException {
        int cPos = data.position();
       
        if (data.remaining() < Integer.SIZE / 8)
            throw new LogEntryException("Empty data. Cannot read log entry.");
       
        int length1 = data.getInt();
       
        if ((length1 - Integer.SIZE / 8) > data.remaining()) {
            data.position(cPos);
            Logging.logMessage(Logging.LEVEL_DEBUG, null, "not long enough");
            throw new LogEntryException("The log entry is incomplete. " +
                "The length indicated in the header exceeds the " +
                "available data.");
        }
       
        data.position(cPos + length1 - Integer.SIZE / 8);
       
        int length2 = data.getInt();
       
        data.position(cPos);
       
        if (length1 != length2) {
            throw new LogEntryException("Invalid Frame. The length entries do" +
                " not match; length1=" + length1 + ", length2=" +
                length2);
        }
       
    }
   
    public static LogEntry deserialize(ReusableBuffer data, Checksum csumAlgo)
        throws LogEntryException {
        checkIntegrity(data);
       
        final int bufSize = data.getInt();
        LogEntry e = new LogEntry();
        e.checksum = data.getInt();
        e.viewId = data.getInt();
        e.logSequenceNo = data.getLong();
        e.payloadType = data.get();
        final int payloadSize = bufSize - headerLength;
        int payloadPosition = data.position();
        ReusableBuffer payload = data.createViewBuffer();
        payload.range(payloadPosition, payloadSize);
        e.payload = payload;
       
        if (USE_CHECKSUMS) {
            // reset the old checksum to 0, before calculating a new one
            data.position(Integer.SIZE / 8);
            data.putInt(0);
            data.position(0);
           
            csumAlgo.update(data.array(), 0, data.limit());
            int csum = (int) csumAlgo.getValue();
           
            if (csum != e.checksum) {
                throw new LogEntryException(
                    "Invalid Checksum. Checksum in log entry and calculated " +
                    "checksum do not match.");
            }
        }
       
        return e;
    }
   
    public void free() {
        BufferPool.free(payload);
        payload = null;
    }
   
    public LSMDBRequest<?> getAttachment() {
        return attachment;
    }
   
    public void setAttachment(LSMDBRequest<?> attachment) {
        this.attachment = attachment;
    }
   
    public byte getPayloadType() {
        return payloadType;
    }
   
    /* (non-Javadoc)
     * @see java.lang.Object#clone()
     */
    @Override
    public LogEntry clone() {
        LogEntry result = new LogEntry(payload.createViewBuffer(), listener, payloadType);
        result.assignId(viewId, logSequenceNo);
        result.attachment = attachment;
        result.checksum = checksum;
        return result;
    }
   
    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "LSN(" + viewId + ":" + logSequenceNo + ") with " + payload.remaining() +
               " bytes of payload.";
    }
}
TOP

Related Classes of org.xtreemfs.babudb.log.LogEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.