Add custom EXI buffer management
[netconf.git] / netconf / netconf-netty-util / src / main / java / org / opendaylight / netconf / nettyutil / handler / ThreadLocalSAXDecoder.java
1 /*
2  * Copyright (c) 2019 Pantheon Technologies, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netconf.nettyutil.handler;
9
10 import java.io.IOException;
11 import org.opendaylight.netconf.shaded.exificient.core.EXIFactory;
12 import org.opendaylight.netconf.shaded.exificient.core.exceptions.EXIException;
13 import org.opendaylight.netconf.shaded.exificient.main.api.sax.SAXDecoder;
14 import org.xml.sax.InputSource;
15 import org.xml.sax.SAXException;
16
17 /**
18  * Utility SAXDecoder, which reuses a thread-local buffer during parse operations.
19  */
20 final class ThreadLocalSAXDecoder extends SAXDecoder {
21     // Note these limits are number of chars, i.e. 2 bytes
22     private static final int INITIAL_SIZE = 4096;
23     private static final int CACHE_MAX_SIZE = 32768;
24     private static final ThreadLocal<char[]> CBUFFER_CACHE = ThreadLocal.withInitial(() -> new char[INITIAL_SIZE]);
25
26     ThreadLocalSAXDecoder(final EXIFactory noOptionsFactory) throws EXIException {
27         super(noOptionsFactory, null);
28     }
29
30     @Override
31     public void parse(final InputSource source) throws IOException, SAXException {
32         cbuffer = CBUFFER_CACHE.get();
33         final int startSize = cbuffer.length;
34         try {
35             super.parse(source);
36         } finally {
37             char[] toCache = cbuffer;
38             cbuffer = null;
39             if (toCache.length > CACHE_MAX_SIZE && startSize < CACHE_MAX_SIZE) {
40                 // The buffer grew to large for caching, but make sure we enlarge our cached buffer to prevent
41                 // some amount of reallocations in future.
42                 toCache = new char[CACHE_MAX_SIZE];
43             }
44             CBUFFER_CACHE.set(toCache);
45         }
46     }
47 }