ByteBufferWriter.java
Go to the documentation of this file.
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf;
32 
33 import static java.lang.Math.max;
34 import static java.lang.Math.min;
35 
36 import java.io.IOException;
37 import java.io.OutputStream;
38 import java.lang.ref.SoftReference;
39 import java.lang.reflect.Field;
40 import java.nio.ByteBuffer;
41 import java.nio.channels.WritableByteChannel;
42 
44 final class ByteBufferWriter {
45  private ByteBufferWriter() {}
46 
51  // TODO(nathanmittler): tune this property or allow configuration?
52  private static final int MIN_CACHED_BUFFER_SIZE = 1024;
53 
58  // TODO(nathanmittler): tune this property or allow configuration?
59  private static final int MAX_CACHED_BUFFER_SIZE = 16 * 1024;
60 
62  // TODO(nathanmittler): tune this property or allow configuration?
63  private static final float BUFFER_REALLOCATION_THRESHOLD = 0.5f;
64 
71  private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
72  new ThreadLocal<SoftReference<byte[]>>();
73 
75  private static final Class<?> FILE_OUTPUT_STREAM_CLASS = safeGetClass("java.io.FileOutputStream");
76 
77  private static final long CHANNEL_FIELD_OFFSET = getChannelFieldOffset(FILE_OUTPUT_STREAM_CLASS);
78 
83  static void clearCachedBuffer() {
84  BUFFER.set(null);
85  }
86 
91  static void write(ByteBuffer buffer, OutputStream output) throws IOException {
92  final int initialPos = buffer.position();
93  try {
94  if (buffer.hasArray()) {
95  // Optimized write for array-backed buffers.
96  // Note that we're taking the risk that a malicious OutputStream could modify the array.
97  output.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
98  } else if (!writeToChannel(buffer, output)) {
99  // Read all of the data from the buffer to an array.
100  // TODO(nathanmittler): Consider performance improvements for other "known" stream types.
101  final byte[] array = getOrCreateBuffer(buffer.remaining());
102  while (buffer.hasRemaining()) {
103  int length = min(buffer.remaining(), array.length);
104  buffer.get(array, 0, length);
105  output.write(array, 0, length);
106  }
107  }
108  } finally {
109  // Restore the initial position.
110  buffer.position(initialPos);
111  }
112  }
113 
114  private static byte[] getOrCreateBuffer(int requestedSize) {
115  requestedSize = max(requestedSize, MIN_CACHED_BUFFER_SIZE);
116 
117  byte[] buffer = getBuffer();
118  // Only allocate if we need to.
119  if (buffer == null || needToReallocate(requestedSize, buffer.length)) {
120  buffer = new byte[requestedSize];
121 
122  // Only cache the buffer if it's not too big.
123  if (requestedSize <= MAX_CACHED_BUFFER_SIZE) {
124  setBuffer(buffer);
125  }
126  }
127  return buffer;
128  }
129 
130  private static boolean needToReallocate(int requestedSize, int bufferLength) {
131  // First check against just the requested length to avoid the multiply.
132  return bufferLength < requestedSize
133  && bufferLength < requestedSize * BUFFER_REALLOCATION_THRESHOLD;
134  }
135 
136  private static byte[] getBuffer() {
137  SoftReference<byte[]> sr = BUFFER.get();
138  return sr == null ? null : sr.get();
139  }
140 
141  private static void setBuffer(byte[] value) {
142  BUFFER.set(new SoftReference<byte[]>(value));
143  }
144 
145  private static boolean writeToChannel(ByteBuffer buffer, OutputStream output) throws IOException {
146  if (CHANNEL_FIELD_OFFSET >= 0 && FILE_OUTPUT_STREAM_CLASS.isInstance(output)) {
147  // Use a channel to write out the ByteBuffer. This will automatically empty the buffer.
148  WritableByteChannel channel = null;
149  try {
150  channel = (WritableByteChannel) UnsafeUtil.getObject(output, CHANNEL_FIELD_OFFSET);
151  } catch (ClassCastException e) {
152  // Absorb.
153  }
154  if (channel != null) {
155  channel.write(buffer);
156  return true;
157  }
158  }
159  return false;
160  }
161 
162  private static Class<?> safeGetClass(String className) {
163  try {
164  return Class.forName(className);
165  } catch (ClassNotFoundException e) {
166  return null;
167  }
168  }
169 
170  private static long getChannelFieldOffset(Class<?> clazz) {
171  try {
172  if (clazz != null && UnsafeUtil.hasUnsafeArrayOperations()) {
173  Field field = clazz.getDeclaredField("channel");
174  return UnsafeUtil.objectFieldOffset(field);
175  }
176  } catch (Throwable e) {
177  // Absorb
178  }
179  return -1;
180  }
181 }
java::lang
length
GLenum GLuint GLenum GLsizei length
Definition: glcorearb.h:2695
java::lang::reflect
buffer
GLuint buffer
Definition: glcorearb.h:2939
buffer::length
size_t length
Definition: buffer_processor.h:45
buffer
Definition: buffer_processor.h:43
field
const FieldDescriptor * field
Definition: parser_unittest.cc:2694
java
Field
Definition: type.pb.h:416
value
GLsizei const GLfloat * value
Definition: glcorearb.h:3093
output
const upb_json_parsermethod const upb_symtab upb_sink * output
Definition: ruby/ext/google/protobuf_c/upb.h:10503
array
PHP_PROTO_OBJECT_FREE_END PHP_PROTO_OBJECT_DTOR_END intern array
Definition: array.c:111


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:48