Question

First of all sorry for my crooked English :)

I have some problems during writing Netty http server that sends/receives large files (~2Gb). And I would very appreciate anybody help or explanation.

My client application (web-browser) sends files via XMLHttpRequest like this:

            var sampleFile = document.getElementById("sampleFile").files[0];  //chosen file by <input type="file" .../>
            var xhr = new XMLHttpRequest();       
            xhr.open("POST","http://127.0.0.1:8091/upload/some_file_name.txt", true);        
            xhr.send(sampleFile);

Server side is:

class WebSocketServer:

             ServerBootstrap bootstrapHttp = new ServerBootstrap(
            new NioServerSocketChannelFactory(
                              Executors.newCachedThreadPool(),
                              Executors.newCachedThreadPool()));

    bootstrapHttp.setPipelineFactory(new ChannelPipelineFactory() {
        public ChannelPipeline getPipeline() {
            ChannelPipeline pipeline = pipeline();

              pipeline.addLast("decoder", new HttpRequestDecoder());
              pipeline.addLast("aggregator", new HttpChunkAggregator(1024*1024*1024));
              pipeline.addLast("encoder", new HttpResponseEncoder());          
              pipeline.addLast("deflater", new HttpContentCompressor());               
              pipeline.addLast("handler", new HttpRequestServerHandler());
              return pipeline;
        }
    });     
    bootstrapHttp.bind(new InetSocketAddress(port));

class HttpRequestServerHandler:

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception    {

             Object msg = e.getMessage();

    if (msg instanceof HttpRequest) {

        HttpRequest req = (HttpRequest)msg;             

        if (req.getMethod() != POST) {          
            return;             
        }                   

        if (decodedURI.startsWith(UPLOAD_FILE_PATH)) {

            HttpRequest request = (HttpRequest) e.getMessage(); 

            RandomAccessFile raf = new RandomAccessFile("foobar.tmp", "rw");                
            ChannelBuffer buf = request.getContent();                   
            FileChannel fChannel = raf.getChannel();
            Channel msgChannel= e.getChannel();             

            fChannel.write( buf.toByteBuffer() );                               
            raf.close();
            fChannel.close();
            msgChannel.close();
        }
    }

When I send middle size file everything works wonderfully. The problem is with large files (>300Mb). After some time processing exception occures:

java.lang.OutOfMemoryError: Java heap space at org.jboss.netty.buffer.HeapChannelBuffer.(HeapChannelBuffer.java:47) at org.jboss.netty.buffer.BigEndianHeapChannelBuffer.(BigEndianHeapChannelBuffer.java:39) at org.jboss.netty.buffer.ChannelBuffers.buffer(ChannelBuffers.java:139) at org.jboss.netty.buffer.HeapChannelBufferFactory.getBuffer(HeapChannelBufferFactory.java:73) at org.jboss.netty.buffer.DynamicChannelBuffer.ensureWritableBytes(DynamicChannelBuffer.java:84) at org.jboss.netty.buffer.DynamicChannelBuffer.writeBytes(DynamicChannelBuffer.java:239) at org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes(AbstractChannelBuffer.java:457) at org.jboss.netty.buffer.AbstractChannelBuffer.writeBytes(AbstractChannelBuffer.java:450) at org.jboss.netty.handler.codec.http.HttpChunkAggregator.messageReceived(HttpChunkAggregator.java:140) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:302) at org.jboss.netty.handler.codec.replay.ReplayingDecoder.unfoldAndFireMessageReceived(ReplayingDecoder.java:522) at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:506) at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:443) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351)

It even don't reach my messageReceived handler. As I can assume some inner ChannelBuffer is overflowed. I've tried to increase HttpChunkAggregator(1024*1024*1024) parameter. However, It would not helped. I see just one solution - to split file on the client side (using html5), send these chunks, and paste them together on server. But its seems to quite complex. Is there any easier way to fix it (in Netty scope)?

Thank you! Best regards.

Was it helpful?

Solution

I think you should not use HttpChunkAggregator.

This means that you will have to manually handle HTTP chunks.

See Netty file upload example for more details.

OTHER TIPS

Yeah a bette way would be to "push" byte[] chunks to the fs until the upload is complete. So you don't need to hold everything in the memory. Be aware that the writing to the fs may "block", so you should think about adding an ExecutionHandler in front of it.

The fact that it's in something called HeapChannelBuffer says a lot - you probably want org.jboss.netty.buffer.DirectChannelBufferFactory somewhere in there, so that your data isn't stored on the heap.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top