All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.protocols.COMPRESS Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 35.0.0.Beta1
Show newest version
package org.jgroups.protocols;

import org.jgroups.Global;
import org.jgroups.Header;
import org.jgroups.Message;
import org.jgroups.annotations.MBean;
import org.jgroups.annotations.Property;
import org.jgroups.stack.Protocol;
import org.jgroups.util.MessageBatch;
import org.jgroups.util.MessageIterator;
import org.jgroups.util.Util;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.function.Supplier;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

/**
 * Compresses the payload of a message. Goal is to reduce the number of messages
 * sent across the wire. Should ideally be layered somewhere above a
 * fragmentation protocol (e.g. FRAG).
 * 
 * @author Bela Ban
 */
@MBean(description="Compresses messages to send and uncompresses received messages")
public class COMPRESS extends Protocol {   

    /* -----------------------------------------    Properties     -------------------------------------------------- */
    
    @Property(description="Compression level (from java.util.zip.Deflater) " +
      "(0=no compression, 1=best speed, 9=best compression). Default is 9")
    protected int compression_level=Deflater.BEST_COMPRESSION; // this is 9
   
    @Property(description="Minimal payload size of a message (in bytes) for compression to kick in. Default is 500 bytes")
    protected long min_size=500;
    
    @Property(description="Number of inflaters/deflaters for concurrent processing. Default is 2 ")
    protected int pool_size=2;
    
    
    /* --------------------------------------------- Fields ------------------------------------------------------ */
    
    
    protected BlockingQueue deflater_pool=null;
    protected BlockingQueue inflater_pool=null;

    

    public COMPRESS() {      
    }


    public void init() throws Exception {
        deflater_pool=new ArrayBlockingQueue<>(pool_size);
        for(int i=0; i < pool_size; i++)
            deflater_pool.add(new Deflater(compression_level));
        inflater_pool=new ArrayBlockingQueue<>(pool_size);
        for(int i=0; i < pool_size; i++)
            inflater_pool.add(new Inflater());
    }

    public void destroy() {
        deflater_pool.forEach(Deflater::end);
        inflater_pool.forEach(Inflater::end);
    }   


    /**
     * We compress the payload if it is larger than {@code min_size}. In this case we add a header containing
     * the original size before compression. Otherwise we add no header.

* Note that we compress either the entire buffer (if offset/length are not used), or a subset (if offset/length * are used) */ public Object down(Message msg) { int length=msg.getLength(); // takes offset/length (if set) into account if(length >= min_size) { byte[] payload=msg.getRawBuffer(); // here we get the ref so we can avoid copying byte[] compressed_payload=new byte[length]; Deflater deflater=null; try { deflater=deflater_pool.take(); deflater.reset(); deflater.setInput(payload, msg.getOffset(), length); deflater.finish(); deflater.deflate(compressed_payload); int compressed_size=deflater.getTotalOut(); if(compressed_size < length ) { // JGRP-1000 Message copy=msg.copy(false).putHeader(this.id,new CompressHeader(length)) .setBuffer(compressed_payload, 0, compressed_size); if(log.isTraceEnabled()) log.trace("compressed payload from %d bytes to %d bytes", length, compressed_size); return down_prot.down(copy); } else { if(log.isTraceEnabled()) log.trace("skipping compression since the compressed message (%d) is not " + "smaller than the original (%d)", compressed_size, length); } } catch(InterruptedException e) { Thread.currentThread().interrupt(); // set interrupt flag again throw new RuntimeException(e); } finally { if(deflater != null) deflater_pool.offer(deflater); } } return down_prot.down(msg); } /** * If there is no header, we pass the message up. Otherwise we uncompress the payload to its original size. */ public Object up(Message msg) { CompressHeader hdr=msg.getHeader(this.id); if(hdr != null) { Message uncompressed_msg=uncompress(msg, hdr.original_size); if(uncompressed_msg != null) { if(log.isTraceEnabled()) log.trace("uncompressed %d bytes to %d bytes", msg.getLength(), uncompressed_msg.getLength()); return up_prot.up(uncompressed_msg); } } return up_prot.up(msg); } public void up(MessageBatch batch) { MessageIterator it=batch.iterator(); while(it.hasNext()) { Message msg=it.next(); CompressHeader hdr=msg.getHeader(this.id); if(hdr != null) { Message uncompressed_msg=uncompress(msg, hdr.original_size); if(uncompressed_msg != null) { if(log.isTraceEnabled()) log.trace("uncompressed %d bytes to %d bytes", msg.getLength(), uncompressed_msg.getLength()); it.replace(uncompressed_msg); // replace msg in batch with uncompressed_msg } } } if(!batch.isEmpty()) up_prot.up(batch); } /** Returns a new message as a result of uncompressing msg, or null if msg couldn't be uncompressed */ protected Message uncompress(Message msg, int original_size) { byte[] compressed_payload=msg.getRawBuffer(); if(compressed_payload != null && compressed_payload.length > 0) { byte[] uncompressed_payload=new byte[original_size]; Inflater inflater=null; try { inflater=inflater_pool.take(); inflater.reset(); inflater.setInput(compressed_payload, msg.getOffset(), msg.getLength()); try { inflater.inflate(uncompressed_payload); // we need to copy: https://jira.jboss.org/jira/browse/JGRP-867 return msg.copy(false).setBuffer(uncompressed_payload); } catch(DataFormatException e) { log.error(Util.getMessage("CompressionFailure"), e); } } catch(InterruptedException e) { Thread.currentThread().interrupt(); // set the interrupt bit again, so caller can handle it } finally { if(inflater != null) inflater_pool.offer(inflater); } } return null; } public static class CompressHeader extends Header { int original_size=0; public CompressHeader() { super(); } public CompressHeader(int s) { original_size=s; } public short getMagicId() {return 58;} public Supplier create() { return CompressHeader::new; } @Override public int serializedSize() { return Global.INT_SIZE; } @Override public void writeTo(DataOutput out) throws IOException { out.writeInt(original_size); } @Override public void readFrom(DataInput in) throws IOException { original_size=in.readInt(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy