Issue #2215 upgrade thrift to version 0.9.0
Change-Id: I9cf910a75c25f1d97a711a9088c3b496ceb2be70 Former-commit-id: ab2e3f3e8910043b117887712258fc689f2e9445
This commit is contained in:
parent
00aeeb338b
commit
8898a6d2ba
182 changed files with 23494 additions and 2739 deletions
|
@ -136,7 +136,7 @@
|
|||
version="0.0.0"/>
|
||||
|
||||
<plugin
|
||||
id="com.facebook.thrift"
|
||||
id="org.apache.thrift"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"/>
|
||||
|
|
|
@ -15,7 +15,6 @@ Require-Bundle: org.eclipse.ui,
|
|||
org.jep,
|
||||
javax.persistence,
|
||||
net.sf.cglib,
|
||||
com.facebook.thrift,
|
||||
com.raytheon.uf.common.localization;visibility:=reexport,
|
||||
com.raytheon.uf.common.serialization;visibility:=reexport,
|
||||
com.raytheon.uf.common.geospatial;bundle-version="1.12.1174";visibility:=reexport,
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Thrift Plug-in
|
||||
Bundle-SymbolicName: com.facebook.thrift
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-ClassPath: libthrift.jar
|
||||
Bundle-Vendor: Raytheon-bundled OSS
|
||||
Export-Package: com.facebook.thrift,
|
||||
com.facebook.thrift.protocol,
|
||||
com.facebook.thrift.reflection.limited,
|
||||
com.facebook.thrift.server,
|
||||
com.facebook.thrift.transport
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
|
@ -1,2 +0,0 @@
|
|||
bin.includes = META-INF/,\
|
||||
libthrift.jar
|
Binary file not shown.
|
@ -6,7 +6,6 @@ Bundle-Version: 1.0.0.qualifier
|
|||
Bundle-ClassPath: log4j-1.2.16.jar,
|
||||
log4j.extras-1.0.jar,
|
||||
.
|
||||
Require-Bundle: javax.jms
|
||||
Export-Package: org.apache.log4j,
|
||||
org.apache.log4j.chainsaw,
|
||||
org.apache.log4j.config,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry exported="true" kind="lib" path="libthrift.jar" sourcepath="com.facebook.thriftsrc.zip"/>
|
||||
<classpathentry exported="true" kind="lib" path="libthrift-0.9.0.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
28
cots/org.apache.thrift/.project
Normal file
28
cots/org.apache.thrift/.project
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.apache.thrift</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -1,5 +1,5 @@
|
|||
#Thu Mar 26 10:10:17 CDT 2009
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
16
cots/org.apache.thrift/META-INF/MANIFEST.MF
Normal file
16
cots/org.apache.thrift/META-INF/MANIFEST.MF
Normal file
|
@ -0,0 +1,16 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Thrift
|
||||
Bundle-SymbolicName: org.apache.thrift
|
||||
Bundle-Version: 0.9.0
|
||||
Bundle-ClassPath: libthrift-0.9.0.jar
|
||||
Bundle-Vendor: Apache
|
||||
Export-Package: org.apache.thrift,
|
||||
org.apache.thrift.async,
|
||||
org.apache.thrift.meta_data,
|
||||
org.apache.thrift.protocol,
|
||||
org.apache.thrift.scheme,
|
||||
org.apache.thrift.server,
|
||||
org.apache.thrift.transport
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Require-Bundle: org.slf4j;bundle-version="1.7.5"
|
2
cots/org.apache.thrift/build.properties
Normal file
2
cots/org.apache.thrift/build.properties
Normal file
|
@ -0,0 +1,2 @@
|
|||
bin.includes = META-INF/,\
|
||||
libthrift-0.9.0.jar
|
BIN
cots/org.apache.thrift/libthrift-0.9.0.jar
Normal file
BIN
cots/org.apache.thrift/libthrift-0.9.0.jar
Normal file
Binary file not shown.
|
@ -34,7 +34,6 @@ Require-Bundle: net.sf.ehcache,
|
|||
javax.measure,
|
||||
org.apache.commons.collections,
|
||||
net.sf.cglib;visibility:=reexport,
|
||||
com.facebook.thrift,
|
||||
javax.persistence,
|
||||
com.raytheon.uf.common.localization,
|
||||
com.raytheon.uf.common.serialization;visibility:=reexport,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
</license>
|
||||
|
||||
<plugin
|
||||
id="com.facebook.thrift"
|
||||
id="org.apache.thrift"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Thrift Plug-in
|
||||
Bundle-Name: Communication Plug-in
|
||||
Bundle-SymbolicName: com.raytheon.uf.common.serialization.comm
|
||||
Bundle-Version: 1.12.1174.qualifier
|
||||
Bundle-Vendor: RAYTHEON
|
||||
|
|
|
@ -5,7 +5,7 @@ Bundle-SymbolicName: com.raytheon.uf.common.serialization
|
|||
Bundle-Version: 1.12.1174.qualifier
|
||||
Bundle-Vendor: Raytheon
|
||||
Eclipse-BuddyPolicy: registered, ext, global
|
||||
Require-Bundle: com.facebook.thrift,
|
||||
Require-Bundle: org.apache.thrift,
|
||||
com.raytheon.uf.common.status,
|
||||
net.sf.cglib;visibility:=reexport,
|
||||
javax.persistence,
|
||||
|
|
|
@ -28,8 +28,6 @@ import java.lang.reflect.Modifier;
|
|||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -56,10 +54,8 @@ import com.raytheon.uf.common.serialization.BuiltInTypeSupport.CalendarSerialize
|
|||
import com.raytheon.uf.common.serialization.BuiltInTypeSupport.DateSerializer;
|
||||
import com.raytheon.uf.common.serialization.BuiltInTypeSupport.TimestampSerializer;
|
||||
import com.raytheon.uf.common.serialization.adapters.BufferAdapter;
|
||||
import com.raytheon.uf.common.serialization.adapters.ByteBufferAdapter;
|
||||
import com.raytheon.uf.common.serialization.adapters.CoordAdapter;
|
||||
import com.raytheon.uf.common.serialization.adapters.EnumSetAdapter;
|
||||
import com.raytheon.uf.common.serialization.adapters.FloatBufferAdapter;
|
||||
import com.raytheon.uf.common.serialization.adapters.GeometryTypeAdapter;
|
||||
import com.raytheon.uf.common.serialization.adapters.GridGeometry2DAdapter;
|
||||
import com.raytheon.uf.common.serialization.adapters.GridGeometryAdapter;
|
||||
|
@ -150,9 +146,6 @@ public class DynamicSerializationManager {
|
|||
registerAdapter(QName.class, new BuiltInTypeSupport.QNameSerializer());
|
||||
registerAdapter(Throwable.class,
|
||||
new BuiltInTypeSupport.ThrowableSerializer());
|
||||
// These two are OBE by BufferAdapter and should be deleted sometime
|
||||
registerAdapter(ByteBuffer.class, new ByteBufferAdapter());
|
||||
registerAdapter(FloatBuffer.class, new FloatBufferAdapter());
|
||||
registerAdapter(Buffer.class, new BufferAdapter());
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
**/
|
||||
package com.raytheon.uf.common.serialization;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Defines the interface for deserialization capability
|
||||
*
|
||||
|
@ -28,6 +30,7 @@ package com.raytheon.uf.common.serialization;
|
|||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 12, 2008 chammack Initial creation
|
||||
* Sep 14, 2012 1169 djohnson Added readObject().
|
||||
* Jul 23, 2013 2215 njensen Added readBuffer()
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -116,6 +119,14 @@ public interface IDeserializationContext {
|
|||
*/
|
||||
byte[] readBinary() throws SerializationException;
|
||||
|
||||
/**
|
||||
* Read a byte buffer
|
||||
*
|
||||
* @return
|
||||
* @throws SerializationException
|
||||
*/
|
||||
ByteBuffer readBuffer() throws SerializationException;
|
||||
|
||||
/**
|
||||
* Read a float array
|
||||
*
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
**/
|
||||
package com.raytheon.uf.common.serialization;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Defines the interface for serialization capability
|
||||
*
|
||||
|
@ -27,7 +29,8 @@ package com.raytheon.uf.common.serialization;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 07, 2008 chammack Initial creation
|
||||
* Sep 14, 2012 1169 djohnson Added writeObject(OBject).
|
||||
* Sep 14, 2012 1169 djohnson Added writeObject(Object).
|
||||
* Jul 23, 2013 2215 njensen Added writeBuffer(ByteBuffer)
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -91,8 +94,7 @@ public interface ISerializationContext {
|
|||
* @param dub
|
||||
* @throws SerializationException
|
||||
*/
|
||||
void writeDoubleArray(double[] dubs)
|
||||
throws SerializationException;
|
||||
void writeDoubleArray(double[] dubs) throws SerializationException;
|
||||
|
||||
/**
|
||||
* Write a float
|
||||
|
@ -118,14 +120,21 @@ public interface ISerializationContext {
|
|||
*/
|
||||
void writeBinary(byte[] bin) throws SerializationException;
|
||||
|
||||
/**
|
||||
* Write a byte buffer
|
||||
*
|
||||
* @param buffer
|
||||
* @throws SerializationException
|
||||
*/
|
||||
void writeBuffer(ByteBuffer buffer) throws SerializationException;
|
||||
|
||||
/**
|
||||
* Write a float array
|
||||
*
|
||||
* @param floats
|
||||
* @throws SerializationException
|
||||
*/
|
||||
void writeFloatArray(float[] floats)
|
||||
throws SerializationException;
|
||||
void writeFloatArray(float[] floats) throws SerializationException;
|
||||
|
||||
/**
|
||||
* Write a message header
|
||||
|
@ -133,8 +142,7 @@ public interface ISerializationContext {
|
|||
* @param messageName
|
||||
* @throws SerializationException
|
||||
*/
|
||||
void writeMessageStart(String messageName)
|
||||
throws SerializationException;
|
||||
void writeMessageStart(String messageName) throws SerializationException;
|
||||
|
||||
/**
|
||||
* Write a message footer
|
||||
|
|
|
@ -43,7 +43,8 @@ import com.raytheon.uf.common.serialization.SerializationException;
|
|||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* May 3, 2012 mschenke Initial creation
|
||||
* May 03, 2012 mschenke Initial creation
|
||||
* Jul 23, 2013 2215 njensen Updated for thrift 0.9.0
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -102,7 +103,8 @@ public class BufferAdapter implements ISerializationTypeAdapter<Buffer> {
|
|||
throw new SerializationException("Could not handle buffer type: "
|
||||
+ buffer.getClass());
|
||||
}
|
||||
serializer.writeBinary(bb.array());
|
||||
bb.rewind();
|
||||
serializer.writeBuffer(bb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -117,10 +119,13 @@ public class BufferAdapter implements ISerializationTypeAdapter<Buffer> {
|
|||
throws SerializationException {
|
||||
boolean direct = deserializer.readBool();
|
||||
byte type = deserializer.readByte();
|
||||
byte[] bytes = deserializer.readBinary();
|
||||
ByteBuffer buffer = direct ? ByteBuffer.allocateDirect(bytes.length)
|
||||
: ByteBuffer.allocate(bytes.length);
|
||||
buffer.put(bytes);
|
||||
ByteBuffer buffer = deserializer.readBuffer();
|
||||
if (buffer.isDirect() != direct) {
|
||||
ByteBuffer copyBuffer = direct ? ByteBuffer.allocateDirect(buffer
|
||||
.capacity()) : ByteBuffer.allocate(buffer.capacity());
|
||||
copyBuffer.put(buffer);
|
||||
buffer = copyBuffer;
|
||||
}
|
||||
buffer.rewind();
|
||||
Buffer dataBuffer = null;
|
||||
switch (type) {
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.common.serialization.adapters;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.raytheon.uf.common.serialization.IDeserializationContext;
|
||||
import com.raytheon.uf.common.serialization.ISerializationContext;
|
||||
import com.raytheon.uf.common.serialization.ISerializationTypeAdapter;
|
||||
import com.raytheon.uf.common.serialization.SerializationException;
|
||||
|
||||
/**
|
||||
* Dynamic serialize adapter for ByteBuffers
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 28, 2009 njensen Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class ByteBufferAdapter implements ISerializationTypeAdapter<ByteBuffer> {
|
||||
|
||||
@Override
|
||||
public ByteBuffer deserialize(IDeserializationContext deserializer)
|
||||
throws SerializationException {
|
||||
ByteBuffer buf = null;
|
||||
|
||||
byte[] b = deserializer.readBinary();
|
||||
buf = ByteBuffer.wrap(b);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ISerializationContext serializer, ByteBuffer buffer)
|
||||
throws SerializationException {
|
||||
byte[] b;
|
||||
if (buffer.hasArray()) {
|
||||
b = buffer.array();
|
||||
} else {
|
||||
b = new byte[buffer.capacity()];
|
||||
((ByteBuffer) buffer.duplicate().rewind()).get(b);
|
||||
}
|
||||
serializer.writeBinary(b);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.common.serialization.adapters;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import com.raytheon.uf.common.serialization.IDeserializationContext;
|
||||
import com.raytheon.uf.common.serialization.ISerializationContext;
|
||||
import com.raytheon.uf.common.serialization.ISerializationTypeAdapter;
|
||||
import com.raytheon.uf.common.serialization.SerializationException;
|
||||
|
||||
/**
|
||||
* Dynamic serialize adapter for FloatBuffers
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 26, 2009 njensen Initial creation
|
||||
* Aug 10, 2009 #2755 chammack Inlined for speed
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class FloatBufferAdapter implements
|
||||
ISerializationTypeAdapter<FloatBuffer> {
|
||||
|
||||
@Override
|
||||
public FloatBuffer deserialize(IDeserializationContext deserializer)
|
||||
throws SerializationException {
|
||||
FloatBuffer buf = null;
|
||||
float[] array = deserializer.readFloatArray();
|
||||
buf = FloatBuffer.wrap(array);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ISerializationContext serializer, FloatBuffer object)
|
||||
throws SerializationException {
|
||||
float[] array = object.array();
|
||||
serializer.writeFloatArray(array);
|
||||
}
|
||||
}
|
|
@ -7,12 +7,12 @@ import java.nio.IntBuffer;
|
|||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import com.facebook.thrift.TException;
|
||||
import com.facebook.thrift.protocol.TBinaryProtocol;
|
||||
import com.facebook.thrift.protocol.TField;
|
||||
import com.facebook.thrift.protocol.TStruct;
|
||||
import com.facebook.thrift.protocol.TType;
|
||||
import com.facebook.thrift.transport.TTransport;
|
||||
import org.apache.thrift.TException;
|
||||
import org.apache.thrift.protocol.TBinaryProtocol;
|
||||
import org.apache.thrift.protocol.TField;
|
||||
import org.apache.thrift.protocol.TStruct;
|
||||
import org.apache.thrift.protocol.TType;
|
||||
import org.apache.thrift.transport.TTransport;
|
||||
|
||||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
|
@ -57,6 +57,7 @@ import com.facebook.thrift.transport.TTransport;
|
|||
* Jun 17, 2010 #5091 njensen Added primitive list methods
|
||||
* Jun 12, 2013 2102 njensen Added max read length to prevent out
|
||||
* of memory errors due to bad stream
|
||||
* Jul 23, 2013 2215 njensen Updated for thrift 0.9.0
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -106,13 +107,14 @@ public class SelfDescribingBinaryProtocol extends TBinaryProtocol {
|
|||
@Override
|
||||
public TField readFieldBegin() throws TException {
|
||||
// This method was overriden to make the structs more self describing
|
||||
TField field = new TField();
|
||||
field.type = readByte();
|
||||
if (field.type != TType.STOP) {
|
||||
field.name = readString();
|
||||
field.id = readI16();
|
||||
Byte type = readByte();
|
||||
String name = "";
|
||||
short id = (short) 0;
|
||||
if (type != TType.STOP) {
|
||||
name = readString();
|
||||
id = readI16();
|
||||
}
|
||||
return field;
|
||||
return new TField(name, type, id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -21,6 +21,7 @@ package com.raytheon.uf.common.serialization.thrift;
|
|||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -34,14 +35,15 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import net.sf.cglib.beans.BeanMap;
|
||||
import net.sf.cglib.reflect.FastClass;
|
||||
|
||||
import com.facebook.thrift.TException;
|
||||
import com.facebook.thrift.protocol.TField;
|
||||
import com.facebook.thrift.protocol.TList;
|
||||
import com.facebook.thrift.protocol.TMap;
|
||||
import com.facebook.thrift.protocol.TMessage;
|
||||
import com.facebook.thrift.protocol.TSet;
|
||||
import com.facebook.thrift.protocol.TStruct;
|
||||
import com.facebook.thrift.protocol.TType;
|
||||
import org.apache.thrift.TException;
|
||||
import org.apache.thrift.protocol.TField;
|
||||
import org.apache.thrift.protocol.TList;
|
||||
import org.apache.thrift.protocol.TMap;
|
||||
import org.apache.thrift.protocol.TMessage;
|
||||
import org.apache.thrift.protocol.TSet;
|
||||
import org.apache.thrift.protocol.TStruct;
|
||||
import org.apache.thrift.protocol.TType;
|
||||
|
||||
import com.raytheon.uf.common.serialization.BaseSerializationContext;
|
||||
import com.raytheon.uf.common.serialization.DynamicSerializationManager;
|
||||
import com.raytheon.uf.common.serialization.DynamicSerializationManager.EnclosureType;
|
||||
|
@ -67,6 +69,7 @@ import com.raytheon.uf.common.serialization.SerializationException;
|
|||
* Sep 28, 2012 #1195 djohnson Add ability to specify adapter at field level.
|
||||
* Nov 02, 2012 1302 djohnson No more field level adapters.
|
||||
* Apr 25, 2013 1954 bsteffen Size Collections better.
|
||||
* Jul 23, 2013 2215 njensen Updated for thrift 0.9.0
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -128,7 +131,7 @@ public class ThriftSerializationContext extends BaseSerializationContext {
|
|||
@Override
|
||||
public byte[] readBinary() throws SerializationException {
|
||||
try {
|
||||
return this.protocol.readBinary();
|
||||
return this.protocol.readBinary().array();
|
||||
} catch (TException e) {
|
||||
throw new SerializationException(e);
|
||||
}
|
||||
|
@ -255,7 +258,7 @@ public class ThriftSerializationContext extends BaseSerializationContext {
|
|||
@Override
|
||||
public void writeBinary(byte[] arg0) throws SerializationException {
|
||||
try {
|
||||
this.protocol.writeBinary(arg0);
|
||||
this.protocol.writeBinary(ByteBuffer.wrap(arg0));
|
||||
} catch (TException e) {
|
||||
throw new SerializationException(e);
|
||||
}
|
||||
|
@ -713,10 +716,7 @@ public class ThriftSerializationContext extends BaseSerializationContext {
|
|||
private boolean serializeField(Object val, Class<?> valClass, byte type,
|
||||
String keyStr, ISerializationTypeAdapter adapter, short id)
|
||||
throws TException, SerializationException {
|
||||
TField field = new TField();
|
||||
field.type = type;
|
||||
field.id = id;
|
||||
field.name = keyStr;
|
||||
TField field = new TField(keyStr, type, id);
|
||||
protocol.writeFieldBegin(field);
|
||||
|
||||
if (type != TType.VOID) {
|
||||
|
@ -1351,4 +1351,22 @@ public class ThriftSerializationContext extends BaseSerializationContext {
|
|||
throw new SerializationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBuffer(ByteBuffer buffer) throws SerializationException {
|
||||
try {
|
||||
this.protocol.writeBinary(buffer);
|
||||
} catch (TException e) {
|
||||
throw new SerializationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer readBuffer() throws SerializationException {
|
||||
try {
|
||||
return this.protocol.readBinary();
|
||||
} catch (TException e) {
|
||||
throw new SerializationException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,9 @@ package com.raytheon.uf.common.serialization.thrift;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.facebook.thrift.transport.TIOStreamTransport;
|
||||
import com.facebook.thrift.transport.TTransport;
|
||||
import org.apache.thrift.transport.TIOStreamTransport;
|
||||
import org.apache.thrift.transport.TTransport;
|
||||
|
||||
import com.raytheon.uf.common.serialization.DynamicSerializationManager;
|
||||
import com.raytheon.uf.common.serialization.IDeserializationContext;
|
||||
import com.raytheon.uf.common.serialization.ISerializationContext;
|
||||
|
@ -37,6 +38,7 @@ import com.raytheon.uf.common.serialization.ISerializationContextBuilder;
|
|||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Aug 12, 2008 chammack Initial creation
|
||||
* Jul 23, 2013 2215 njensen Updated for thrift 0.9.0
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -67,7 +69,8 @@ public class ThriftSerializationContextBuilder implements
|
|||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.edex.serialize.ISerializationContextBuilder#buildSerializationContext()
|
||||
* @see com.raytheon.edex.serialize.ISerializationContextBuilder#
|
||||
* buildSerializationContext()
|
||||
*/
|
||||
@Override
|
||||
public ISerializationContext buildSerializationContext(OutputStream data,
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
Version = 0.5.0
|
||||
|
||||
Origin
|
||||
------
|
||||
http://archive.apache.org/dist/incubator/thrift/0.5.0-incubating/
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <thrift/TApplicationException.h>
|
||||
#include <thrift/protocol/TProtocol.h>
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
||||
uint32_t TApplicationException::read(apache::thrift::protocol::TProtocol* iprot) {
|
||||
uint32_t xfer = 0;
|
||||
std::string fname;
|
||||
apache::thrift::protocol::TType ftype;
|
||||
int16_t fid;
|
||||
|
||||
xfer += iprot->readStructBegin(fname);
|
||||
|
||||
while (true) {
|
||||
xfer += iprot->readFieldBegin(fname, ftype, fid);
|
||||
if (ftype == apache::thrift::protocol::T_STOP) {
|
||||
break;
|
||||
}
|
||||
switch (fid) {
|
||||
case 1:
|
||||
if (ftype == apache::thrift::protocol::T_STRING) {
|
||||
xfer += iprot->readString(message_);
|
||||
} else {
|
||||
xfer += iprot->skip(ftype);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (ftype == apache::thrift::protocol::T_I32) {
|
||||
int32_t type;
|
||||
xfer += iprot->readI32(type);
|
||||
type_ = (TApplicationExceptionType)type;
|
||||
} else {
|
||||
xfer += iprot->skip(ftype);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
xfer += iprot->skip(ftype);
|
||||
break;
|
||||
}
|
||||
xfer += iprot->readFieldEnd();
|
||||
}
|
||||
|
||||
xfer += iprot->readStructEnd();
|
||||
return xfer;
|
||||
}
|
||||
|
||||
uint32_t TApplicationException::write(apache::thrift::protocol::TProtocol* oprot) const {
|
||||
uint32_t xfer = 0;
|
||||
xfer += oprot->writeStructBegin("TApplicationException");
|
||||
xfer += oprot->writeFieldBegin("message", apache::thrift::protocol::T_STRING, 1);
|
||||
xfer += oprot->writeString(message_);
|
||||
xfer += oprot->writeFieldEnd();
|
||||
xfer += oprot->writeFieldBegin("type", apache::thrift::protocol::T_I32, 2);
|
||||
xfer += oprot->writeI32(type_);
|
||||
xfer += oprot->writeFieldEnd();
|
||||
xfer += oprot->writeFieldStop();
|
||||
xfer += oprot->writeStructEnd();
|
||||
return xfer;
|
||||
}
|
||||
|
||||
}} // apache::thrift
|
|
@ -20,7 +20,7 @@
|
|||
#ifndef _THRIFT_TAPPLICATIONEXCEPTION_H_
|
||||
#define _THRIFT_TAPPLICATIONEXCEPTION_H_ 1
|
||||
|
||||
#include <Thrift.h>
|
||||
#include <thrift/Thrift.h>
|
||||
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
@ -41,7 +41,9 @@ class TApplicationException : public TException {
|
|||
INVALID_MESSAGE_TYPE = 2,
|
||||
WRONG_METHOD_NAME = 3,
|
||||
BAD_SEQUENCE_ID = 4,
|
||||
MISSING_RESULT = 5
|
||||
MISSING_RESULT = 5,
|
||||
INTERNAL_ERROR = 6,
|
||||
PROTOCOL_ERROR = 7
|
||||
};
|
||||
|
||||
TApplicationException() :
|
||||
|
|
142
nativeLib/org.apache.thrift/include/TDispatchProcessor.h
Normal file
142
nativeLib/org.apache.thrift/include/TDispatchProcessor.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
#ifndef _THRIFT_TDISPATCHPROCESSOR_H_
|
||||
#define _THRIFT_TDISPATCHPROCESSOR_H_ 1
|
||||
|
||||
#include "TProcessor.h"
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
||||
/**
|
||||
* TDispatchProcessor is a helper class to parse the message header then call
|
||||
* another function to dispatch based on the function name.
|
||||
*
|
||||
* Subclasses must implement dispatchCall() to dispatch on the function name.
|
||||
*/
|
||||
template <class Protocol_>
|
||||
class TDispatchProcessorT : public TProcessor {
|
||||
public:
|
||||
virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
|
||||
boost::shared_ptr<protocol::TProtocol> out,
|
||||
void* connectionContext) {
|
||||
protocol::TProtocol* inRaw = in.get();
|
||||
protocol::TProtocol* outRaw = out.get();
|
||||
|
||||
// Try to dynamic cast to the template protocol type
|
||||
Protocol_* specificIn = dynamic_cast<Protocol_*>(inRaw);
|
||||
Protocol_* specificOut = dynamic_cast<Protocol_*>(outRaw);
|
||||
if (specificIn && specificOut) {
|
||||
return processFast(specificIn, specificOut, connectionContext);
|
||||
}
|
||||
|
||||
// Log the fact that we have to use the slow path
|
||||
T_GENERIC_PROTOCOL(this, inRaw, specificIn);
|
||||
T_GENERIC_PROTOCOL(this, outRaw, specificOut);
|
||||
|
||||
std::string fname;
|
||||
protocol::TMessageType mtype;
|
||||
int32_t seqid;
|
||||
inRaw->readMessageBegin(fname, mtype, seqid);
|
||||
|
||||
// If this doesn't look like a valid call, log an error and return false so
|
||||
// that the server will close the connection.
|
||||
//
|
||||
// (The old generated processor code used to try to skip a T_STRUCT and
|
||||
// continue. However, that seems unsafe.)
|
||||
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
|
||||
GlobalOutput.printf("received invalid message type %d from client",
|
||||
mtype);
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->dispatchCall(inRaw, outRaw, fname, seqid, connectionContext);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool processFast(Protocol_* in, Protocol_* out, void* connectionContext) {
|
||||
std::string fname;
|
||||
protocol::TMessageType mtype;
|
||||
int32_t seqid;
|
||||
in->readMessageBegin(fname, mtype, seqid);
|
||||
|
||||
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
|
||||
GlobalOutput.printf("received invalid message type %d from client",
|
||||
mtype);
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->dispatchCallTemplated(in, out, fname,
|
||||
seqid, connectionContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatchCall() methods must be implemented by subclasses
|
||||
*/
|
||||
virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in,
|
||||
apache::thrift::protocol::TProtocol* out,
|
||||
const std::string& fname, int32_t seqid,
|
||||
void* callContext) = 0;
|
||||
|
||||
virtual bool dispatchCallTemplated(Protocol_* in, Protocol_* out,
|
||||
const std::string& fname, int32_t seqid,
|
||||
void* callContext) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Non-templatized version of TDispatchProcessor, that doesn't bother trying to
|
||||
* perform a dynamic_cast.
|
||||
*/
|
||||
class TDispatchProcessor : public TProcessor {
|
||||
public:
|
||||
virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
|
||||
boost::shared_ptr<protocol::TProtocol> out,
|
||||
void* connectionContext) {
|
||||
std::string fname;
|
||||
protocol::TMessageType mtype;
|
||||
int32_t seqid;
|
||||
in->readMessageBegin(fname, mtype, seqid);
|
||||
|
||||
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
|
||||
GlobalOutput.printf("received invalid message type %d from client",
|
||||
mtype);
|
||||
return false;
|
||||
}
|
||||
|
||||
return dispatchCall(in.get(), out.get(), fname, seqid, connectionContext);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in,
|
||||
apache::thrift::protocol::TProtocol* out,
|
||||
const std::string& fname, int32_t seqid,
|
||||
void* callContext) = 0;
|
||||
};
|
||||
|
||||
// Specialize TDispatchProcessorT for TProtocol and TDummyProtocol just to use
|
||||
// the generic TDispatchProcessor.
|
||||
template <>
|
||||
class TDispatchProcessorT<protocol::TDummyProtocol> :
|
||||
public TDispatchProcessor {};
|
||||
template <>
|
||||
class TDispatchProcessorT<protocol::TProtocol> :
|
||||
public TDispatchProcessor {};
|
||||
|
||||
}} // apache::thrift
|
||||
|
||||
#endif // _THRIFT_TDISPATCHPROCESSOR_H_
|
|
@ -63,7 +63,7 @@
|
|||
#if T_GLOBAL_DEBUGGING_LEVEL > 0
|
||||
#define T_DEBUG(format_string,...) \
|
||||
if (T_GLOBAL_DEBUGGING_LEVEL > 0) { \
|
||||
fprintf(stderr,"[%s,%d] " #format_string " \n", __FILE__, __LINE__,##__VA_ARGS__); \
|
||||
fprintf(stderr,"[%s,%d] " format_string " \n", __FILE__, __LINE__,##__VA_ARGS__); \
|
||||
}
|
||||
#else
|
||||
#define T_DEBUG(format_string,...)
|
||||
|
@ -84,7 +84,7 @@
|
|||
time(&now); \
|
||||
ctime_r(&now, dbgtime); \
|
||||
dbgtime[24] = '\0'; \
|
||||
fprintf(stderr,"[%s,%d] [%s] " #format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
|
||||
fprintf(stderr,"[%s,%d] [%s] " format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
|
@ -101,7 +101,7 @@
|
|||
*/
|
||||
#define T_DEBUG_L(level, format_string,...) \
|
||||
if ((level) > 0) { \
|
||||
fprintf(stderr,"[%s,%d] " #format_string " \n", __FILE__, __LINE__,##__VA_ARGS__); \
|
||||
fprintf(stderr,"[%s,%d] " format_string " \n", __FILE__, __LINE__,##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
|
||||
|
@ -117,7 +117,7 @@
|
|||
time(&now); \
|
||||
ctime_r(&now, dbgtime); \
|
||||
dbgtime[24] = '\0'; \
|
||||
fprintf(stderr,"[%s,%d] [%s] ERROR: " #format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
|
||||
fprintf(stderr,"[%s,%d] [%s] ERROR: " format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,7 +134,7 @@
|
|||
time(&now); \
|
||||
ctime_r(&now, dbgtime); \
|
||||
dbgtime[24] = '\0'; \
|
||||
fprintf(stderr,"[%s,%d] [%s] ERROR: Going to abort " #format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
|
||||
fprintf(stderr,"[%s,%d] [%s] ERROR: Going to abort " format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
|
@ -153,11 +153,47 @@
|
|||
time(&now); \
|
||||
ctime_r(&now, dbgtime); \
|
||||
dbgtime[24] = '\0'; \
|
||||
fprintf(stderr,"[%s] " #format_string " \n", dbgtime,##__VA_ARGS__); \
|
||||
fprintf(stderr,"[%s] " format_string " \n", dbgtime,##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define T_LOG_OPER(format_string,...)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* T_GLOBAL_DEBUG_VIRTUAL = 0 or unset: normal operation,
|
||||
* virtual call debug messages disabled
|
||||
* T_GLOBAL_DEBUG_VIRTUAL = 1: log a debug messages whenever an
|
||||
* avoidable virtual call is made
|
||||
* T_GLOBAL_DEBUG_VIRTUAL = 2: record detailed info that can be
|
||||
* printed by calling
|
||||
* apache::thrift::profile_print_info()
|
||||
*/
|
||||
#if T_GLOBAL_DEBUG_VIRTUAL > 1
|
||||
#define T_VIRTUAL_CALL() \
|
||||
::apache::thrift::profile_virtual_call(typeid(*this))
|
||||
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) \
|
||||
do { \
|
||||
if (!(specific_prot)) { \
|
||||
::apache::thrift::profile_generic_protocol( \
|
||||
typeid(*template_class), typeid(*generic_prot)); \
|
||||
} \
|
||||
} while (0)
|
||||
#elif T_GLOBAL_DEBUG_VIRTUAL == 1
|
||||
#define T_VIRTUAL_CALL() \
|
||||
fprintf(stderr,"[%s,%d] virtual call\n", __FILE__, __LINE__)
|
||||
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) \
|
||||
do { \
|
||||
if (!(specific_prot)) { \
|
||||
fprintf(stderr, \
|
||||
"[%s,%d] failed to cast to specific protocol type\n", \
|
||||
__FILE__, __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define T_VIRTUAL_CALL()
|
||||
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)
|
||||
#endif
|
||||
|
||||
#endif // #ifndef _THRIFT_TLOGGING_H_
|
||||
|
|
|
@ -21,11 +21,112 @@
|
|||
#define _THRIFT_TPROCESSOR_H_ 1
|
||||
|
||||
#include <string>
|
||||
#include <protocol/TProtocol.h>
|
||||
#include <thrift/protocol/TProtocol.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
||||
/**
|
||||
* Virtual interface class that can handle events from the processor. To
|
||||
* use this you should subclass it and implement the methods that you care
|
||||
* about. Your subclass can also store local data that you may care about,
|
||||
* such as additional "arguments" to these methods (stored in the object
|
||||
* instance's state).
|
||||
*/
|
||||
class TProcessorEventHandler {
|
||||
public:
|
||||
|
||||
virtual ~TProcessorEventHandler() {}
|
||||
|
||||
/**
|
||||
* Called before calling other callback methods.
|
||||
* Expected to return some sort of context object.
|
||||
* The return value is passed to all other callbacks
|
||||
* for that function invocation.
|
||||
*/
|
||||
virtual void* getContext(const char* fn_name, void* serverContext) {
|
||||
(void) fn_name;
|
||||
(void) serverContext;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expected to free resources associated with a context.
|
||||
*/
|
||||
virtual void freeContext(void* ctx, const char* fn_name) {
|
||||
(void) ctx;
|
||||
(void) fn_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before reading arguments.
|
||||
*/
|
||||
virtual void preRead(void* ctx, const char* fn_name) {
|
||||
(void) ctx;
|
||||
(void) fn_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called between reading arguments and calling the handler.
|
||||
*/
|
||||
virtual void postRead(void* ctx, const char* fn_name, uint32_t bytes) {
|
||||
(void) ctx;
|
||||
(void) fn_name;
|
||||
(void) bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called between calling the handler and writing the response.
|
||||
*/
|
||||
virtual void preWrite(void* ctx, const char* fn_name) {
|
||||
(void) ctx;
|
||||
(void) fn_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after writing the response.
|
||||
*/
|
||||
virtual void postWrite(void* ctx, const char* fn_name, uint32_t bytes) {
|
||||
(void) ctx;
|
||||
(void) fn_name;
|
||||
(void) bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an async function call completes successfully.
|
||||
*/
|
||||
virtual void asyncComplete(void* ctx, const char* fn_name) {
|
||||
(void) ctx;
|
||||
(void) fn_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called if the handler throws an undeclared exception.
|
||||
*/
|
||||
virtual void handlerError(void* ctx, const char* fn_name) {
|
||||
(void) ctx;
|
||||
(void) fn_name;
|
||||
}
|
||||
|
||||
protected:
|
||||
TProcessorEventHandler() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper class used by the generated code to free each context.
|
||||
*/
|
||||
class TProcessorContextFreer {
|
||||
public:
|
||||
TProcessorContextFreer(TProcessorEventHandler* handler, void* context, const char* method) :
|
||||
handler_(handler), context_(context), method_(method) {}
|
||||
~TProcessorContextFreer() { if (handler_ != NULL) handler_->freeContext(context_, method_); }
|
||||
void unregister() { handler_ = NULL; }
|
||||
private:
|
||||
apache::thrift::TProcessorEventHandler* handler_;
|
||||
void* context_;
|
||||
const char* method_;
|
||||
};
|
||||
|
||||
/**
|
||||
* A processor is a generic object that acts upon two streams of data, one
|
||||
* an input and the other an output. The definition of this object is loose,
|
||||
|
@ -38,16 +139,95 @@ class TProcessor {
|
|||
virtual ~TProcessor() {}
|
||||
|
||||
virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
|
||||
boost::shared_ptr<protocol::TProtocol> out) = 0;
|
||||
boost::shared_ptr<protocol::TProtocol> out,
|
||||
void* connectionContext) = 0;
|
||||
|
||||
bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> io) {
|
||||
return process(io, io);
|
||||
bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> io,
|
||||
void* connectionContext) {
|
||||
return process(io, io, connectionContext);
|
||||
}
|
||||
|
||||
boost::shared_ptr<TProcessorEventHandler> getEventHandler() {
|
||||
return eventHandler_;
|
||||
}
|
||||
|
||||
void setEventHandler(boost::shared_ptr<TProcessorEventHandler> eventHandler) {
|
||||
eventHandler_ = eventHandler;
|
||||
}
|
||||
|
||||
protected:
|
||||
TProcessor() {}
|
||||
|
||||
boost::shared_ptr<TProcessorEventHandler> eventHandler_;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a helper class to allow boost::shared_ptr to be used with handler
|
||||
* pointers returned by the generated handler factories.
|
||||
*
|
||||
* The handler factory classes generated by the thrift compiler return raw
|
||||
* pointers, and factory->releaseHandler() must be called when the handler is
|
||||
* no longer needed.
|
||||
*
|
||||
* A ReleaseHandler object can be instantiated and passed as the second
|
||||
* parameter to a shared_ptr, so that factory->releaseHandler() will be called
|
||||
* when the object is no longer needed, instead of deleting the pointer.
|
||||
*/
|
||||
template<typename HandlerFactory_>
|
||||
class ReleaseHandler {
|
||||
public:
|
||||
ReleaseHandler(const boost::shared_ptr<HandlerFactory_>& handlerFactory) :
|
||||
handlerFactory_(handlerFactory) {}
|
||||
|
||||
void operator()(typename HandlerFactory_::Handler* handler) {
|
||||
if (handler) {
|
||||
handlerFactory_->releaseHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
boost::shared_ptr<HandlerFactory_> handlerFactory_;
|
||||
};
|
||||
|
||||
struct TConnectionInfo {
|
||||
// The input and output protocols
|
||||
boost::shared_ptr<protocol::TProtocol> input;
|
||||
boost::shared_ptr<protocol::TProtocol> output;
|
||||
// The underlying transport used for the connection
|
||||
// This is the transport that was returned by TServerTransport::accept(),
|
||||
// and it may be different than the transport pointed to by the input and
|
||||
// output protocols.
|
||||
boost::shared_ptr<transport::TTransport> transport;
|
||||
};
|
||||
|
||||
class TProcessorFactory {
|
||||
public:
|
||||
virtual ~TProcessorFactory() {}
|
||||
|
||||
/**
|
||||
* Get the TProcessor to use for a particular connection.
|
||||
*
|
||||
* This method is always invoked in the same thread that the connection was
|
||||
* accepted on. This generally means that this call does not need to be
|
||||
* thread safe, as it will always be invoked from a single thread.
|
||||
*/
|
||||
virtual boost::shared_ptr<TProcessor> getProcessor(
|
||||
const TConnectionInfo& connInfo) = 0;
|
||||
};
|
||||
|
||||
class TSingletonProcessorFactory : public TProcessorFactory {
|
||||
public:
|
||||
TSingletonProcessorFactory(boost::shared_ptr<TProcessor> processor) :
|
||||
processor_(processor) {}
|
||||
|
||||
boost::shared_ptr<TProcessor> getProcessor(const TConnectionInfo&) {
|
||||
return processor_;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::shared_ptr<TProcessor> processor_;
|
||||
};
|
||||
|
||||
}} // apache::thrift
|
||||
|
||||
#endif // #ifndef _THRIFT_PROCESSOR_H_
|
||||
#endif // #ifndef _THRIFT_TPROCESSOR_H_
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <cstring>
|
||||
#include <protocol/TProtocol.h>
|
||||
#include <thrift/protocol/TProtocol.h>
|
||||
|
||||
/**
|
||||
* Local Reflection is a blanket term referring to the the structure
|
||||
|
|
93
nativeLib/org.apache.thrift/include/Thrift.cpp
Normal file
93
nativeLib/org.apache.thrift/include/Thrift.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <thrift/Thrift.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
||||
TOutput GlobalOutput;
|
||||
|
||||
void TOutput::printf(const char *message, ...) {
|
||||
// Try to reduce heap usage, even if printf is called rarely.
|
||||
static const int STACK_BUF_SIZE = 256;
|
||||
char stack_buf[STACK_BUF_SIZE];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, message);
|
||||
int need = vsnprintf(stack_buf, STACK_BUF_SIZE, message, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (need < STACK_BUF_SIZE) {
|
||||
f_(stack_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
char *heap_buf = (char*)malloc((need+1) * sizeof(char));
|
||||
if (heap_buf == NULL) {
|
||||
// Malloc failed. We might as well print the stack buffer.
|
||||
f_(stack_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(ap, message);
|
||||
int rval = vsnprintf(heap_buf, need+1, message, ap);
|
||||
va_end(ap);
|
||||
// TODO(shigin): inform user
|
||||
if (rval != -1) {
|
||||
f_(heap_buf);
|
||||
}
|
||||
free(heap_buf);
|
||||
}
|
||||
|
||||
void TOutput::perror(const char *message, int errno_copy) {
|
||||
std::string out = message + strerror_s(errno_copy);
|
||||
f_(out.c_str());
|
||||
}
|
||||
|
||||
std::string TOutput::strerror_s(int errno_copy) {
|
||||
#ifndef HAVE_STRERROR_R
|
||||
return "errno = " + boost::lexical_cast<std::string>(errno_copy);
|
||||
#else // HAVE_STRERROR_R
|
||||
|
||||
char b_errbuf[1024] = { '\0' };
|
||||
#ifdef STRERROR_R_CHAR_P
|
||||
char *b_error = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));
|
||||
#else
|
||||
char *b_error = b_errbuf;
|
||||
int rv = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));
|
||||
if (rv == -1) {
|
||||
// strerror_r failed. omgwtfbbq.
|
||||
return "XSI-compliant strerror_r() failed with errno = " +
|
||||
boost::lexical_cast<std::string>(errno_copy);
|
||||
}
|
||||
#endif
|
||||
// Can anyone prove that explicit cast is probably not necessary
|
||||
// to ensure that the string object is constructed before
|
||||
// b_error becomes invalid?
|
||||
return std::string(b_error);
|
||||
|
||||
#endif // HAVE_STRERROR_R
|
||||
}
|
||||
|
||||
}} // apache::thrift
|
|
@ -20,13 +20,20 @@
|
|||
#ifndef _THRIFT_THRIFT_H_
|
||||
#define _THRIFT_THRIFT_H_ 1
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <thrift/windows/config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
@ -36,11 +43,65 @@
|
|||
#include <set>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
|
||||
#include "TLogging.h"
|
||||
|
||||
/**
|
||||
* Helper macros to allow function overloading even when using
|
||||
* boost::shared_ptr.
|
||||
*
|
||||
* shared_ptr makes overloading really annoying, since shared_ptr defines
|
||||
* constructor methods to allow one shared_ptr type to be constructed from any
|
||||
* other shared_ptr type. (Even if it would be a compile error to actually try
|
||||
* to instantiate the constructor.) These macros add an extra argument to the
|
||||
* function to cause it to only be instantiated if a pointer of type T is
|
||||
* convertible to a pointer of type U.
|
||||
*
|
||||
* THRIFT_OVERLOAD_IF should be used in function declarations.
|
||||
* THRIFT_OVERLOAD_IF_DEFN should be used in the function definition, if it is
|
||||
* defined separately from where it is declared.
|
||||
*/
|
||||
#define THRIFT_OVERLOAD_IF_DEFN(T, Y) \
|
||||
typename ::boost::enable_if<typename ::boost::is_convertible<T*, Y*>::type, \
|
||||
void*>::type
|
||||
|
||||
#define THRIFT_OVERLOAD_IF(T, Y) \
|
||||
THRIFT_OVERLOAD_IF_DEFN(T, Y) = NULL
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
||||
class TEnumIterator : public std::iterator<std::forward_iterator_tag, std::pair<int, const char*> > {
|
||||
public:
|
||||
TEnumIterator(int n,
|
||||
int* enums,
|
||||
const char** names) :
|
||||
ii_(0), n_(n), enums_(enums), names_(names) {
|
||||
}
|
||||
|
||||
int operator ++() {
|
||||
return ++ii_;
|
||||
}
|
||||
|
||||
bool operator !=(const TEnumIterator& end) {
|
||||
assert(end.n_ == -1);
|
||||
return (ii_ != n_);
|
||||
}
|
||||
|
||||
std::pair<int, const char*> operator*() const {
|
||||
return std::make_pair(enums_[ii_], names_[ii_]);
|
||||
}
|
||||
|
||||
private:
|
||||
int ii_;
|
||||
const int n_;
|
||||
int* enums_;
|
||||
const char** names_;
|
||||
};
|
||||
|
||||
class TOutput {
|
||||
public:
|
||||
TOutput() : f_(&errorTimeWrapper) {}
|
||||
|
@ -84,7 +145,8 @@ extern TOutput GlobalOutput;
|
|||
|
||||
class TException : public std::exception {
|
||||
public:
|
||||
TException() {}
|
||||
TException():
|
||||
message_() {}
|
||||
|
||||
TException(const std::string& message) :
|
||||
message_(message) {}
|
||||
|
@ -110,6 +172,38 @@ namespace reflection { namespace local {
|
|||
struct TypeSpec;
|
||||
}}
|
||||
|
||||
class TDelayedException {
|
||||
public:
|
||||
template <class E> static TDelayedException* delayException(const E& e);
|
||||
virtual void throw_it() = 0;
|
||||
virtual ~TDelayedException() {};
|
||||
};
|
||||
|
||||
template <class E> class TExceptionWrapper : public TDelayedException {
|
||||
public:
|
||||
TExceptionWrapper(const E& e) : e_(e) {}
|
||||
virtual void throw_it() {
|
||||
E temp(e_);
|
||||
delete this;
|
||||
throw temp;
|
||||
}
|
||||
private:
|
||||
E e_;
|
||||
};
|
||||
|
||||
template <class E>
|
||||
TDelayedException* TDelayedException::delayException(const E& e) {
|
||||
return new TExceptionWrapper<E>(e);
|
||||
}
|
||||
|
||||
#if T_GLOBAL_DEBUG_VIRTUAL > 1
|
||||
void profile_virtual_call(const std::type_info& info);
|
||||
void profile_generic_protocol(const std::type_info& template_type,
|
||||
const std::type_info& prot_type);
|
||||
void profile_print_info(FILE *f);
|
||||
void profile_print_info();
|
||||
void profile_write_pprof(FILE* gen_calls_f, FILE* virtual_calls_f);
|
||||
#endif
|
||||
|
||||
}} // apache::thrift
|
||||
|
||||
|
|
455
nativeLib/org.apache.thrift/include/VirtualProfiling.cpp
Normal file
455
nativeLib/org.apache.thrift/include/VirtualProfiling.cpp
Normal file
|
@ -0,0 +1,455 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <thrift/Thrift.h>
|
||||
|
||||
// Do nothing if virtual call profiling is not enabled
|
||||
#if T_GLOBAL_DEBUG_VIRTUAL > 1
|
||||
|
||||
// TODO: This code only works with g++ (since we rely on the fact
|
||||
// that all std::type_info instances referring to a particular type
|
||||
// always return the exact same pointer value from name().)
|
||||
#ifndef __GNUG__
|
||||
#error "Thrift virtual function profiling currently only works with gcc"
|
||||
#endif // !__GNUG__
|
||||
|
||||
// TODO: We also require glibc for the backtrace() and backtrace_symbols()
|
||||
// functions.
|
||||
#ifndef __GLIBC__
|
||||
#error "Thrift virtual function profiling currently requires glibc"
|
||||
#endif // !__GLIBC__
|
||||
|
||||
|
||||
#include <thrift/concurrency/Mutex.h>
|
||||
|
||||
#include <ext/hash_map>
|
||||
#include <execinfo.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
||||
using ::apache::thrift::concurrency::Mutex;
|
||||
using ::apache::thrift::concurrency::Guard;
|
||||
|
||||
static const unsigned int MAX_STACK_DEPTH = 15;
|
||||
|
||||
/**
|
||||
* A stack trace
|
||||
*/
|
||||
class Backtrace {
|
||||
public:
|
||||
Backtrace(int skip = 0);
|
||||
Backtrace(Backtrace const &bt);
|
||||
|
||||
void operator=(Backtrace const &bt) {
|
||||
numCallers_ = bt.numCallers_;
|
||||
if (numCallers_ >= 0) {
|
||||
memcpy(callers_, bt.callers_, numCallers_ * sizeof(void*));
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(Backtrace const &bt) const {
|
||||
return (cmp(bt) == 0);
|
||||
}
|
||||
|
||||
size_t hash() const {
|
||||
intptr_t ret = 0;
|
||||
for (int n = 0; n < numCallers_; ++n) {
|
||||
ret ^= reinterpret_cast<intptr_t>(callers_[n]);
|
||||
}
|
||||
return static_cast<size_t>(ret);
|
||||
}
|
||||
|
||||
int cmp(Backtrace const& bt) const {
|
||||
int depth_diff = (numCallers_ - bt.numCallers_);
|
||||
if (depth_diff != 0) {
|
||||
return depth_diff;
|
||||
}
|
||||
|
||||
for (int n = 0; n < numCallers_; ++n) {
|
||||
int diff = reinterpret_cast<intptr_t>(callers_[n]) -
|
||||
reinterpret_cast<intptr_t>(bt.callers_[n]);
|
||||
if (diff != 0) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print(FILE *f, int indent=0, int start=0) const {
|
||||
char **strings = backtrace_symbols(callers_, numCallers_);
|
||||
if (strings) {
|
||||
start += skip_;
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
for (int n = start; n < numCallers_; ++n) {
|
||||
fprintf(f, "%*s#%-2d %s\n", indent, "", n, strings[n]);
|
||||
}
|
||||
free(strings);
|
||||
} else {
|
||||
fprintf(f, "%*s<failed to determine symbols>\n", indent, "");
|
||||
}
|
||||
}
|
||||
|
||||
int getDepth() const {
|
||||
return numCallers_ - skip_;
|
||||
}
|
||||
|
||||
void *getFrame(int index) const {
|
||||
int adjusted_index = index + skip_;
|
||||
if (adjusted_index < 0 || adjusted_index >= numCallers_) {
|
||||
return NULL;
|
||||
}
|
||||
return callers_[adjusted_index];
|
||||
}
|
||||
|
||||
private:
|
||||
void *callers_[MAX_STACK_DEPTH];
|
||||
int numCallers_;
|
||||
int skip_;
|
||||
};
|
||||
|
||||
// Define the constructors non-inline, so they consistently add a single
|
||||
// frame to the stack trace, regardless of whether optimization is enabled
|
||||
Backtrace::Backtrace(int skip)
|
||||
: skip_(skip + 1) // ignore the constructor itself
|
||||
{
|
||||
numCallers_ = backtrace(callers_, MAX_STACK_DEPTH);
|
||||
if (skip_ > numCallers_) {
|
||||
skip_ = numCallers_;
|
||||
}
|
||||
}
|
||||
|
||||
Backtrace::Backtrace(Backtrace const &bt)
|
||||
: numCallers_(bt.numCallers_)
|
||||
, skip_(bt.skip_) {
|
||||
if (numCallers_ >= 0) {
|
||||
memcpy(callers_, bt.callers_, numCallers_ * sizeof(void*));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A backtrace, plus one or two type names
|
||||
*/
|
||||
class Key {
|
||||
public:
|
||||
class Hash {
|
||||
public:
|
||||
size_t operator()(Key const& k) const {
|
||||
return k.hash();
|
||||
}
|
||||
};
|
||||
|
||||
Key(const Backtrace* bt, const std::type_info& type_info)
|
||||
: backtrace_(bt)
|
||||
, typeName1_(type_info.name())
|
||||
, typeName2_(NULL) {
|
||||
}
|
||||
|
||||
Key(const Backtrace* bt, const std::type_info& type_info1,
|
||||
const std::type_info& type_info2)
|
||||
: backtrace_(bt)
|
||||
, typeName1_(type_info1.name())
|
||||
, typeName2_(type_info2.name()) {
|
||||
}
|
||||
|
||||
Key(const Key& k)
|
||||
: backtrace_(k.backtrace_)
|
||||
, typeName1_(k.typeName1_)
|
||||
, typeName2_(k.typeName2_) {
|
||||
}
|
||||
|
||||
void operator=(const Key& k) {
|
||||
backtrace_ = k.backtrace_;
|
||||
typeName1_ = k.typeName1_;
|
||||
typeName2_ = k.typeName2_;
|
||||
}
|
||||
|
||||
const Backtrace* getBacktrace() const {
|
||||
return backtrace_;
|
||||
}
|
||||
|
||||
const char* getTypeName() const {
|
||||
return typeName1_;
|
||||
}
|
||||
|
||||
const char* getTypeName2() const {
|
||||
return typeName2_;
|
||||
}
|
||||
|
||||
void makePersistent() {
|
||||
// Copy the Backtrace object
|
||||
backtrace_ = new Backtrace(*backtrace_);
|
||||
|
||||
// NOTE: We don't copy the type name.
|
||||
// The GNU libstdc++ implementation of type_info::name() returns a value
|
||||
// that will be valid for the lifetime of the program. (Although the C++
|
||||
// standard doesn't guarantee this will be true on all implementations.)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up memory allocated by makePersistent()
|
||||
*
|
||||
* Should only be invoked if makePersistent() has previously been called.
|
||||
* The Key should no longer be used after cleanup() is called.
|
||||
*/
|
||||
void cleanup() {
|
||||
delete backtrace_;
|
||||
backtrace_ = NULL;
|
||||
}
|
||||
|
||||
int cmp(const Key& k) const {
|
||||
int ret = backtrace_->cmp(*k.backtrace_);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// NOTE: We compare just the name pointers.
|
||||
// With GNU libstdc++, every type_info object for the same type points to
|
||||
// exactly the same name string. (Although this isn't guaranteed by the
|
||||
// C++ standard.)
|
||||
ret = k.typeName1_ - typeName1_;
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
return k.typeName2_ - typeName2_;
|
||||
}
|
||||
|
||||
bool operator==(const Key& k) const {
|
||||
return cmp(k) == 0;
|
||||
}
|
||||
|
||||
size_t hash() const {
|
||||
// NOTE: As above, we just use the name pointer value.
|
||||
// Works with GNU libstdc++, but not guaranteed to be correct on all
|
||||
// implementations.
|
||||
return backtrace_->hash() ^
|
||||
reinterpret_cast<size_t>(typeName1_) ^
|
||||
reinterpret_cast<size_t>(typeName2_);
|
||||
}
|
||||
|
||||
private:
|
||||
const Backtrace* backtrace_;
|
||||
const char* typeName1_;
|
||||
const char* typeName2_;
|
||||
};
|
||||
|
||||
/**
|
||||
* A functor that determines which of two BacktraceMap entries
|
||||
* has a higher count.
|
||||
*/
|
||||
class CountGreater {
|
||||
public:
|
||||
bool operator()(std::pair<Key, size_t> bt1,
|
||||
std::pair<Key, size_t> bt2) const {
|
||||
return bt1.second > bt2.second;
|
||||
}
|
||||
};
|
||||
|
||||
typedef __gnu_cxx::hash_map<Key, size_t, Key::Hash> BacktraceMap;
|
||||
|
||||
/**
|
||||
* A map describing how many times T_VIRTUAL_CALL() has been invoked.
|
||||
*/
|
||||
BacktraceMap virtual_calls;
|
||||
Mutex virtual_calls_mutex;
|
||||
|
||||
/**
|
||||
* A map describing how many times T_GENERIC_PROTOCOL() has been invoked.
|
||||
*/
|
||||
BacktraceMap generic_calls;
|
||||
Mutex generic_calls_mutex;
|
||||
|
||||
|
||||
void _record_backtrace(BacktraceMap* map, const Mutex& mutex, Key *k) {
|
||||
Guard guard(mutex);
|
||||
|
||||
BacktraceMap::iterator it = map->find(*k);
|
||||
if (it == map->end()) {
|
||||
k->makePersistent();
|
||||
map->insert(std::make_pair(*k, 1));
|
||||
} else {
|
||||
// increment the count
|
||||
// NOTE: we could assert if it->second is 0 afterwards, since that would
|
||||
// mean we've wrapped.
|
||||
++(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record an unnecessary virtual function call.
|
||||
*
|
||||
* This method is invoked by the T_VIRTUAL_CALL() macro.
|
||||
*/
|
||||
void profile_virtual_call(const std::type_info& type) {
|
||||
int const skip = 1; // ignore this frame
|
||||
Backtrace bt(skip);
|
||||
Key k(&bt, type);
|
||||
_record_backtrace(&virtual_calls, virtual_calls_mutex, &k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a call to a template processor with a protocol that is not the one
|
||||
* specified in the template parameter.
|
||||
*
|
||||
* This method is invoked by the T_GENERIC_PROTOCOL() macro.
|
||||
*/
|
||||
void profile_generic_protocol(const std::type_info& template_type,
|
||||
const std::type_info& prot_type) {
|
||||
int const skip = 1; // ignore this frame
|
||||
Backtrace bt(skip);
|
||||
Key k(&bt, template_type, prot_type);
|
||||
_record_backtrace(&generic_calls, generic_calls_mutex, &k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the recorded profiling information to the specified file.
|
||||
*/
|
||||
void profile_print_info(FILE* f) {
|
||||
typedef std::vector< std::pair<Key, size_t> > BacktraceVector;
|
||||
|
||||
CountGreater is_greater;
|
||||
|
||||
// Grab both locks for the duration of the print operation,
|
||||
// to ensure the output is a consistent snapshot of a single point in time
|
||||
Guard generic_calls_guard(generic_calls_mutex);
|
||||
Guard virtual_calls_guard(virtual_calls_mutex);
|
||||
|
||||
// print the info from generic_calls, sorted by frequency
|
||||
//
|
||||
// We print the generic_calls info ahead of virtual_calls, since it is more
|
||||
// useful in some cases. All T_GENERIC_PROTOCOL calls can be eliminated
|
||||
// from most programs. Not all T_VIRTUAL_CALLs will be eliminated by
|
||||
// converting to templates.
|
||||
BacktraceVector gp_sorted(generic_calls.begin(), generic_calls.end());
|
||||
std::sort(gp_sorted.begin(), gp_sorted.end(), is_greater);
|
||||
|
||||
for (BacktraceVector::const_iterator it = gp_sorted.begin();
|
||||
it != gp_sorted.end();
|
||||
++it) {
|
||||
Key const &key = it->first;
|
||||
size_t const count = it->second;
|
||||
fprintf(f, "T_GENERIC_PROTOCOL: %zu calls to %s with a %s:\n",
|
||||
count, key.getTypeName(), key.getTypeName2());
|
||||
key.getBacktrace()->print(f, 2);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
// print the info from virtual_calls, sorted by frequency
|
||||
BacktraceVector vc_sorted(virtual_calls.begin(), virtual_calls.end());
|
||||
std::sort(vc_sorted.begin(), vc_sorted.end(), is_greater);
|
||||
|
||||
for (BacktraceVector::const_iterator it = vc_sorted.begin();
|
||||
it != vc_sorted.end();
|
||||
++it) {
|
||||
Key const &key = it->first;
|
||||
size_t const count = it->second;
|
||||
fprintf(f, "T_VIRTUAL_CALL: %zu calls on %s:\n", count, key.getTypeName());
|
||||
key.getBacktrace()->print(f, 2);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the recorded profiling information to stdout.
|
||||
*/
|
||||
void profile_print_info() {
|
||||
profile_print_info(stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a BacktraceMap as Google CPU profiler binary data.
|
||||
*/
|
||||
static void profile_write_pprof_file(FILE* f, BacktraceMap const& map) {
|
||||
// Write the header
|
||||
uintptr_t header[5] = { 0, 3, 0, 0, 0 };
|
||||
fwrite(&header, sizeof(header), 1, f);
|
||||
|
||||
// Write the profile records
|
||||
for (BacktraceMap::const_iterator it = map.begin(); it != map.end(); ++it) {
|
||||
uintptr_t count = it->second;
|
||||
fwrite(&count, sizeof(count), 1, f);
|
||||
|
||||
Backtrace const* bt = it->first.getBacktrace();
|
||||
uintptr_t num_pcs = bt->getDepth();
|
||||
fwrite(&num_pcs, sizeof(num_pcs), 1, f);
|
||||
|
||||
for (uintptr_t n = 0; n < num_pcs; ++n) {
|
||||
void* pc = bt->getFrame(n);
|
||||
fwrite(&pc, sizeof(pc), 1, f);
|
||||
}
|
||||
}
|
||||
|
||||
// Write the trailer
|
||||
uintptr_t trailer[3] = { 0, 1, 0 };
|
||||
fwrite(&trailer, sizeof(trailer), 1, f);
|
||||
|
||||
// Write /proc/self/maps
|
||||
// TODO(simpkins): This only works on linux
|
||||
FILE *proc_maps = fopen("/proc/self/maps", "r");
|
||||
if (proc_maps) {
|
||||
uint8_t buf[4096];
|
||||
while (true) {
|
||||
size_t bytes_read = fread(buf, 1, sizeof(buf), proc_maps);
|
||||
if (bytes_read == 0) {
|
||||
break;
|
||||
}
|
||||
fwrite(buf, 1, bytes_read, f);
|
||||
}
|
||||
fclose(proc_maps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the recorded profiling information as pprof files.
|
||||
*
|
||||
* This writes the information using the Google CPU profiler binary data
|
||||
* format, so it can be analyzed with pprof. Note that information about the
|
||||
* protocol/transport data types cannot be stored in this file format.
|
||||
*
|
||||
* See http://code.google.com/p/google-perftools/ for more details.
|
||||
*
|
||||
* @param gen_calls_f The information about calls to
|
||||
* profile_generic_protocol() will be written to this
|
||||
* file.
|
||||
* @param virtual_calls_f The information about calls to
|
||||
* profile_virtual_call() will be written to this file.
|
||||
*/
|
||||
void profile_write_pprof(FILE* gen_calls_f, FILE* virtual_calls_f) {
|
||||
typedef std::vector< std::pair<Key, size_t> > BacktraceVector;
|
||||
|
||||
CountGreater is_greater;
|
||||
|
||||
// Grab both locks for the duration of the print operation,
|
||||
// to ensure the output is a consistent snapshot of a single point in time
|
||||
Guard generic_calls_guard(generic_calls_mutex);
|
||||
Guard virtual_calls_guard(virtual_calls_mutex);
|
||||
|
||||
// write the info from generic_calls
|
||||
profile_write_pprof_file(gen_calls_f, generic_calls);
|
||||
|
||||
// write the info from virtual_calls
|
||||
profile_write_pprof_file(virtual_calls_f, virtual_calls);
|
||||
}
|
||||
|
||||
}} // apache::thrift
|
||||
|
||||
#endif // T_GLOBAL_PROFILE_VIRTUAL > 0
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_TASYNC_BUFFER_PROCESSOR_H_
|
||||
#define _THRIFT_TASYNC_BUFFER_PROCESSOR_H_ 1
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <thrift/transport/TBufferTransports.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
class TAsyncBufferProcessor {
|
||||
public:
|
||||
// Process data in "in", putting the result in "out".
|
||||
// Call _return(true) when done, or _return(false) to
|
||||
// forcefully close the connection (if applicable).
|
||||
// "in" and "out" should be TMemoryBuffer or similar,
|
||||
// not a wrapper around a socket.
|
||||
virtual void process(
|
||||
std::tr1::function<void(bool healthy)> _return,
|
||||
boost::shared_ptr<apache::thrift::transport::TBufferBase> ibuf,
|
||||
boost::shared_ptr<apache::thrift::transport::TBufferBase> obuf) = 0;
|
||||
virtual ~TAsyncBufferProcessor() {}
|
||||
};
|
||||
|
||||
}}} // apache::thrift::async
|
||||
|
||||
#endif // #ifndef _THRIFT_TASYNC_BUFFER_PROCESSOR_H_
|
34
nativeLib/org.apache.thrift/include/async/TAsyncChannel.cpp
Normal file
34
nativeLib/org.apache.thrift/include/async/TAsyncChannel.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <thrift/async/TAsyncChannel.h>
|
||||
#include <tr1/functional>
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
void TAsyncChannel::sendAndRecvMessage(const VoidCallback& cob,
|
||||
TMemoryBuffer* sendBuf,
|
||||
TMemoryBuffer* recvBuf) {
|
||||
std::tr1::function<void()> send_done =
|
||||
std::tr1::bind(&TAsyncChannel::recvMessage, this, cob, recvBuf);
|
||||
|
||||
sendMessage(send_done, sendBuf);
|
||||
}
|
||||
|
||||
}}} // apache::thrift::async
|
66
nativeLib/org.apache.thrift/include/async/TAsyncChannel.h
Normal file
66
nativeLib/org.apache.thrift/include/async/TAsyncChannel.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_ASYNC_TASYNCCHANNEL_H_
|
||||
#define _THRIFT_ASYNC_TASYNCCHANNEL_H_ 1
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <thrift/Thrift.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace transport {
|
||||
class TMemoryBuffer;
|
||||
}}}
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
using apache::thrift::transport::TMemoryBuffer;
|
||||
|
||||
class TAsyncChannel {
|
||||
public:
|
||||
typedef std::tr1::function<void()> VoidCallback;
|
||||
|
||||
virtual ~TAsyncChannel() {}
|
||||
|
||||
// is the channel in a good state?
|
||||
virtual bool good() const = 0;
|
||||
virtual bool error() const = 0;
|
||||
virtual bool timedOut() const = 0;
|
||||
|
||||
/**
|
||||
* Send a message over the channel.
|
||||
*/
|
||||
virtual void sendMessage(const VoidCallback& cob,
|
||||
apache::thrift::transport::TMemoryBuffer* message) = 0;
|
||||
|
||||
/**
|
||||
* Receive a message from the channel.
|
||||
*/
|
||||
virtual void recvMessage(const VoidCallback& cob,
|
||||
apache::thrift::transport::TMemoryBuffer* message) = 0;
|
||||
|
||||
/**
|
||||
* Send a message over the channel and receive a response.
|
||||
*/
|
||||
virtual void sendAndRecvMessage(const VoidCallback& cob,
|
||||
apache::thrift::transport::TMemoryBuffer* sendBuf,
|
||||
apache::thrift::transport::TMemoryBuffer* recvBuf);
|
||||
};
|
||||
|
||||
}}} // apache::thrift::async
|
||||
|
||||
#endif // #ifndef _THRIFT_ASYNC_TASYNCCHANNEL_H_
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
#ifndef _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_
|
||||
#define _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_ 1
|
||||
|
||||
#include "TAsyncProcessor.h"
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
/**
|
||||
* TAsyncDispatchProcessor is a helper class to parse the message header then
|
||||
* call another function to dispatch based on the function name.
|
||||
*
|
||||
* Subclasses must implement dispatchCall() to dispatch on the function name.
|
||||
*/
|
||||
template <class Protocol_>
|
||||
class TAsyncDispatchProcessorT : public TAsyncProcessor {
|
||||
public:
|
||||
virtual void process(std::tr1::function<void(bool success)> _return,
|
||||
boost::shared_ptr<protocol::TProtocol> in,
|
||||
boost::shared_ptr<protocol::TProtocol> out) {
|
||||
protocol::TProtocol* inRaw = in.get();
|
||||
protocol::TProtocol* outRaw = out.get();
|
||||
|
||||
// Try to dynamic cast to the template protocol type
|
||||
Protocol_* specificIn = dynamic_cast<Protocol_*>(inRaw);
|
||||
Protocol_* specificOut = dynamic_cast<Protocol_*>(outRaw);
|
||||
if (specificIn && specificOut) {
|
||||
return processFast(_return, specificIn, specificOut);
|
||||
}
|
||||
|
||||
// Log the fact that we have to use the slow path
|
||||
T_GENERIC_PROTOCOL(this, inRaw, specificIn);
|
||||
T_GENERIC_PROTOCOL(this, outRaw, specificOut);
|
||||
|
||||
std::string fname;
|
||||
protocol::TMessageType mtype;
|
||||
int32_t seqid;
|
||||
inRaw->readMessageBegin(fname, mtype, seqid);
|
||||
|
||||
// If this doesn't look like a valid call, log an error and return false so
|
||||
// that the server will close the connection.
|
||||
//
|
||||
// (The old generated processor code used to try to skip a T_STRUCT and
|
||||
// continue. However, that seems unsafe.)
|
||||
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
|
||||
GlobalOutput.printf("received invalid message type %d from client",
|
||||
mtype);
|
||||
_return(false);
|
||||
return;
|
||||
}
|
||||
|
||||
return this->dispatchCall(_return, inRaw, outRaw, fname, seqid);
|
||||
}
|
||||
|
||||
void processFast(std::tr1::function<void(bool success)> _return,
|
||||
Protocol_* in, Protocol_* out) {
|
||||
std::string fname;
|
||||
protocol::TMessageType mtype;
|
||||
int32_t seqid;
|
||||
in->readMessageBegin(fname, mtype, seqid);
|
||||
|
||||
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
|
||||
GlobalOutput.printf("received invalid message type %d from client",
|
||||
mtype);
|
||||
_return(false);
|
||||
return;
|
||||
}
|
||||
|
||||
return this->dispatchCallTemplated(_return, in, out, fname, seqid);
|
||||
}
|
||||
|
||||
virtual void dispatchCall(std::tr1::function<void(bool ok)> _return,
|
||||
apache::thrift::protocol::TProtocol* in,
|
||||
apache::thrift::protocol::TProtocol* out,
|
||||
const std::string& fname, int32_t seqid) = 0;
|
||||
|
||||
virtual void dispatchCallTemplated(std::tr1::function<void(bool ok)> _return,
|
||||
Protocol_* in, Protocol_* out,
|
||||
const std::string& fname,
|
||||
int32_t seqid) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Non-templatized version of TAsyncDispatchProcessor,
|
||||
* that doesn't bother trying to perform a dynamic_cast.
|
||||
*/
|
||||
class TAsyncDispatchProcessor : public TAsyncProcessor {
|
||||
public:
|
||||
virtual void process(std::tr1::function<void(bool success)> _return,
|
||||
boost::shared_ptr<protocol::TProtocol> in,
|
||||
boost::shared_ptr<protocol::TProtocol> out) {
|
||||
protocol::TProtocol* inRaw = in.get();
|
||||
protocol::TProtocol* outRaw = out.get();
|
||||
|
||||
std::string fname;
|
||||
protocol::TMessageType mtype;
|
||||
int32_t seqid;
|
||||
inRaw->readMessageBegin(fname, mtype, seqid);
|
||||
|
||||
// If this doesn't look like a valid call, log an error and return false so
|
||||
// that the server will close the connection.
|
||||
//
|
||||
// (The old generated processor code used to try to skip a T_STRUCT and
|
||||
// continue. However, that seems unsafe.)
|
||||
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
|
||||
GlobalOutput.printf("received invalid message type %d from client",
|
||||
mtype);
|
||||
_return(false);
|
||||
return;
|
||||
}
|
||||
|
||||
return dispatchCall(_return, inRaw, outRaw, fname, seqid);
|
||||
}
|
||||
|
||||
virtual void dispatchCall(std::tr1::function<void(bool ok)> _return,
|
||||
apache::thrift::protocol::TProtocol* in,
|
||||
apache::thrift::protocol::TProtocol* out,
|
||||
const std::string& fname, int32_t seqid) = 0;
|
||||
};
|
||||
|
||||
// Specialize TAsyncDispatchProcessorT for TProtocol and TDummyProtocol just to
|
||||
// use the generic TDispatchProcessor.
|
||||
template <>
|
||||
class TAsyncDispatchProcessorT<protocol::TDummyProtocol> :
|
||||
public TAsyncDispatchProcessor {};
|
||||
template <>
|
||||
class TAsyncDispatchProcessorT<protocol::TProtocol> :
|
||||
public TAsyncDispatchProcessor {};
|
||||
|
||||
}}} // apache::thrift::async
|
||||
|
||||
#endif // _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_
|
97
nativeLib/org.apache.thrift/include/async/TAsyncProcessor.h
Normal file
97
nativeLib/org.apache.thrift/include/async/TAsyncProcessor.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_TASYNCPROCESSOR_H_
|
||||
#define _THRIFT_TASYNCPROCESSOR_H_ 1
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <thrift/protocol/TProtocol.h>
|
||||
#include <thrift/TProcessor.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
/**
|
||||
* Async version of a TProcessor. It is not expected to complete by the time
|
||||
* the call to process returns. Instead, it calls a cob to signal completion.
|
||||
*/
|
||||
|
||||
class TEventServer; // forward declaration
|
||||
|
||||
class TAsyncProcessor {
|
||||
public:
|
||||
virtual ~TAsyncProcessor() {}
|
||||
|
||||
virtual void process(std::tr1::function<void(bool success)> _return,
|
||||
boost::shared_ptr<protocol::TProtocol> in,
|
||||
boost::shared_ptr<protocol::TProtocol> out) = 0;
|
||||
|
||||
void process(std::tr1::function<void(bool success)> _return,
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocol> io) {
|
||||
return process(_return, io, io);
|
||||
}
|
||||
|
||||
boost::shared_ptr<TProcessorEventHandler> getEventHandler() {
|
||||
return eventHandler_;
|
||||
}
|
||||
|
||||
void setEventHandler(boost::shared_ptr<TProcessorEventHandler> eventHandler) {
|
||||
eventHandler_ = eventHandler;
|
||||
}
|
||||
|
||||
const TEventServer* getAsyncServer() {
|
||||
return asyncServer_;
|
||||
}
|
||||
protected:
|
||||
TAsyncProcessor() {}
|
||||
|
||||
boost::shared_ptr<TProcessorEventHandler> eventHandler_;
|
||||
const TEventServer* asyncServer_;
|
||||
private:
|
||||
friend class TEventServer;
|
||||
void setAsyncServer(const TEventServer* server) {
|
||||
asyncServer_ = server;
|
||||
}
|
||||
};
|
||||
|
||||
class TAsyncProcessorFactory {
|
||||
public:
|
||||
virtual ~TAsyncProcessorFactory() {}
|
||||
|
||||
/**
|
||||
* Get the TAsyncProcessor to use for a particular connection.
|
||||
*
|
||||
* This method is always invoked in the same thread that the connection was
|
||||
* accepted on. This generally means that this call does not need to be
|
||||
* thread safe, as it will always be invoked from a single thread.
|
||||
*/
|
||||
virtual boost::shared_ptr<TAsyncProcessor> getProcessor(
|
||||
const TConnectionInfo& connInfo) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}}} // apache::thrift::async
|
||||
|
||||
// XXX I'm lazy for now
|
||||
namespace apache { namespace thrift {
|
||||
using apache::thrift::async::TAsyncProcessor;
|
||||
}}
|
||||
|
||||
#endif // #ifndef _THRIFT_TASYNCPROCESSOR_H_
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "TAsyncProtocolProcessor.h"
|
||||
|
||||
using apache::thrift::transport::TBufferBase;
|
||||
using apache::thrift::protocol::TProtocol;
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
void TAsyncProtocolProcessor::process(
|
||||
std::tr1::function<void(bool healthy)> _return,
|
||||
boost::shared_ptr<TBufferBase> ibuf,
|
||||
boost::shared_ptr<TBufferBase> obuf) {
|
||||
boost::shared_ptr<TProtocol> iprot(pfact_->getProtocol(ibuf));
|
||||
boost::shared_ptr<TProtocol> oprot(pfact_->getProtocol(obuf));
|
||||
return underlying_->process(
|
||||
std::tr1::bind(
|
||||
&TAsyncProtocolProcessor::finish,
|
||||
_return,
|
||||
oprot,
|
||||
std::tr1::placeholders::_1),
|
||||
iprot, oprot);
|
||||
}
|
||||
|
||||
/* static */ void TAsyncProtocolProcessor::finish(
|
||||
std::tr1::function<void(bool healthy)> _return,
|
||||
boost::shared_ptr<TProtocol> oprot,
|
||||
bool healthy) {
|
||||
(void) oprot;
|
||||
// This is a stub function to hold a reference to oprot.
|
||||
return _return(healthy);
|
||||
}
|
||||
|
||||
}}} // apache::thrift::async
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_TNAME_ME_H_
|
||||
#define _THRIFT_TNAME_ME_H_ 1
|
||||
|
||||
#include "TAsyncProcessor.h"
|
||||
#include "TAsyncBufferProcessor.h"
|
||||
#include <thrift/protocol/TProtocol.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
class TAsyncProtocolProcessor : public TAsyncBufferProcessor {
|
||||
public:
|
||||
TAsyncProtocolProcessor(
|
||||
boost::shared_ptr<TAsyncProcessor> underlying,
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact)
|
||||
: underlying_(underlying)
|
||||
, pfact_(pfact)
|
||||
{}
|
||||
|
||||
virtual void process(
|
||||
std::tr1::function<void(bool healthy)> _return,
|
||||
boost::shared_ptr<apache::thrift::transport::TBufferBase> ibuf,
|
||||
boost::shared_ptr<apache::thrift::transport::TBufferBase> obuf);
|
||||
|
||||
virtual ~TAsyncProtocolProcessor() {}
|
||||
|
||||
private:
|
||||
static void finish(
|
||||
std::tr1::function<void(bool healthy)> _return,
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocol> oprot,
|
||||
bool healthy);
|
||||
|
||||
boost::shared_ptr<TAsyncProcessor> underlying_;
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact_;
|
||||
};
|
||||
|
||||
}}} // apache::thrift::async
|
||||
|
||||
#endif // #ifndef _THRIFT_TNAME_ME_H_
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "TEvhttpClientChannel.h"
|
||||
#include <evhttp.h>
|
||||
#include <thrift/transport/TBufferTransports.h>
|
||||
#include <thrift/protocol/TProtocolException.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace apache::thrift::protocol;
|
||||
using apache::thrift::transport::TTransportException;
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
|
||||
TEvhttpClientChannel::TEvhttpClientChannel(
|
||||
const std::string& host,
|
||||
const std::string& path,
|
||||
const char* address,
|
||||
int port,
|
||||
struct event_base* eb)
|
||||
: host_(host)
|
||||
, path_(path)
|
||||
, recvBuf_(NULL)
|
||||
, conn_(NULL)
|
||||
{
|
||||
conn_ = evhttp_connection_new(address, port);
|
||||
if (conn_ == NULL) {
|
||||
throw TException("evhttp_connection_new failed");
|
||||
}
|
||||
evhttp_connection_set_base(conn_, eb);
|
||||
}
|
||||
|
||||
|
||||
TEvhttpClientChannel::~TEvhttpClientChannel() {
|
||||
if (conn_ != NULL) {
|
||||
evhttp_connection_free(conn_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TEvhttpClientChannel::sendAndRecvMessage(
|
||||
const VoidCallback& cob,
|
||||
apache::thrift::transport::TMemoryBuffer* sendBuf,
|
||||
apache::thrift::transport::TMemoryBuffer* recvBuf) {
|
||||
cob_ = cob;
|
||||
recvBuf_ = recvBuf;
|
||||
|
||||
struct evhttp_request* req = evhttp_request_new(response, this);
|
||||
if (req == NULL) {
|
||||
throw TException("evhttp_request_new failed");
|
||||
}
|
||||
|
||||
int rv;
|
||||
|
||||
rv = evhttp_add_header(req->output_headers, "Host", host_.c_str());
|
||||
if (rv != 0) {
|
||||
throw TException("evhttp_add_header failed");
|
||||
}
|
||||
|
||||
rv = evhttp_add_header(req->output_headers, "Content-Type", "application/x-thrift");
|
||||
if (rv != 0) {
|
||||
throw TException("evhttp_add_header failed");
|
||||
}
|
||||
|
||||
uint8_t* obuf;
|
||||
uint32_t sz;
|
||||
sendBuf->getBuffer(&obuf, &sz);
|
||||
rv = evbuffer_add(req->output_buffer, obuf, sz);
|
||||
if (rv != 0) {
|
||||
throw TException("evbuffer_add failed");
|
||||
}
|
||||
|
||||
rv = evhttp_make_request(conn_, req, EVHTTP_REQ_POST, path_.c_str());
|
||||
if (rv != 0) {
|
||||
throw TException("evhttp_make_request failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TEvhttpClientChannel::sendMessage(
|
||||
const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message) {
|
||||
(void) cob;
|
||||
(void) message;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"Unexpected call to TEvhttpClientChannel::sendMessage");
|
||||
}
|
||||
|
||||
|
||||
void TEvhttpClientChannel::recvMessage(
|
||||
const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message) {
|
||||
(void) cob;
|
||||
(void) message;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"Unexpected call to TEvhttpClientChannel::recvMessage");
|
||||
}
|
||||
|
||||
|
||||
void TEvhttpClientChannel::finish(struct evhttp_request* req) {
|
||||
if (req == NULL) {
|
||||
try {
|
||||
cob_();
|
||||
} catch(const TTransportException& e) {
|
||||
if(e.getType() == TTransportException::END_OF_FILE)
|
||||
throw TException("connect failed");
|
||||
else
|
||||
throw;
|
||||
}
|
||||
return;
|
||||
} else if (req->response_code != 200) {
|
||||
try {
|
||||
cob_();
|
||||
} catch(const TTransportException& e) {
|
||||
std::stringstream ss;
|
||||
ss << "server returned code " << req->response_code;
|
||||
if(req->response_code_line)
|
||||
ss << ": " << req->response_code_line;
|
||||
if(e.getType() == TTransportException::END_OF_FILE)
|
||||
throw TException(ss.str());
|
||||
else
|
||||
throw;
|
||||
}
|
||||
return;
|
||||
}
|
||||
recvBuf_->resetBuffer(
|
||||
EVBUFFER_DATA(req->input_buffer),
|
||||
EVBUFFER_LENGTH(req->input_buffer));
|
||||
cob_();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* static */ void TEvhttpClientChannel::response(struct evhttp_request* req, void* arg) {
|
||||
TEvhttpClientChannel* self = (TEvhttpClientChannel*)arg;
|
||||
try {
|
||||
self->finish(req);
|
||||
} catch(std::exception& e) {
|
||||
// don't propagate a C++ exception in C code (e.g. libevent)
|
||||
std::cerr << "TEvhttpClientChannel::response exception thrown (ignored): " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}} // apache::thrift::async
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_
|
||||
#define _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_ 1
|
||||
|
||||
#include <string>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "TAsyncChannel.h"
|
||||
|
||||
struct event_base;
|
||||
struct evhttp_connection;
|
||||
struct evhttp_request;
|
||||
|
||||
namespace apache { namespace thrift { namespace transport {
|
||||
class TMemoryBuffer;
|
||||
}}}
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
class TEvhttpClientChannel : public TAsyncChannel {
|
||||
public:
|
||||
using TAsyncChannel::VoidCallback;
|
||||
|
||||
TEvhttpClientChannel(
|
||||
const std::string& host,
|
||||
const std::string& path,
|
||||
const char* address,
|
||||
int port,
|
||||
struct event_base* eb);
|
||||
~TEvhttpClientChannel();
|
||||
|
||||
virtual void sendAndRecvMessage(const VoidCallback& cob,
|
||||
apache::thrift::transport::TMemoryBuffer* sendBuf,
|
||||
apache::thrift::transport::TMemoryBuffer* recvBuf);
|
||||
|
||||
virtual void sendMessage(const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message);
|
||||
virtual void recvMessage(const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message);
|
||||
|
||||
void finish(struct evhttp_request* req);
|
||||
|
||||
//XXX
|
||||
virtual bool good() const { return true; }
|
||||
virtual bool error() const { return false; }
|
||||
virtual bool timedOut() const { return false; }
|
||||
|
||||
private:
|
||||
static void response(struct evhttp_request* req, void* arg);
|
||||
|
||||
std::string host_;
|
||||
std::string path_;
|
||||
VoidCallback cob_;
|
||||
apache::thrift::transport::TMemoryBuffer* recvBuf_;
|
||||
struct evhttp_connection* conn_;
|
||||
|
||||
};
|
||||
|
||||
}}} // apache::thrift::async
|
||||
|
||||
#endif // #ifndef _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_
|
169
nativeLib/org.apache.thrift/include/async/TEvhttpServer.cpp
Normal file
169
nativeLib/org.apache.thrift/include/async/TEvhttpServer.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "TEvhttpServer.h"
|
||||
#include "TAsyncBufferProcessor.h"
|
||||
#include <thrift/transport/TBufferTransports.h>
|
||||
#include <evhttp.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifndef HTTP_INTERNAL // libevent < 2
|
||||
#define HTTP_INTERNAL 500
|
||||
#endif
|
||||
|
||||
using apache::thrift::transport::TMemoryBuffer;
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
|
||||
struct TEvhttpServer::RequestContext {
|
||||
struct evhttp_request* req;
|
||||
boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> ibuf;
|
||||
boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> obuf;
|
||||
|
||||
RequestContext(struct evhttp_request* req);
|
||||
};
|
||||
|
||||
|
||||
TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor)
|
||||
: processor_(processor)
|
||||
, eb_(NULL)
|
||||
, eh_(NULL)
|
||||
{}
|
||||
|
||||
|
||||
TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor, int port)
|
||||
: processor_(processor)
|
||||
, eb_(NULL)
|
||||
, eh_(NULL)
|
||||
{
|
||||
// Create event_base and evhttp.
|
||||
eb_ = event_base_new();
|
||||
if (eb_ == NULL) {
|
||||
throw TException("event_base_new failed");
|
||||
}
|
||||
eh_ = evhttp_new(eb_);
|
||||
if (eh_ == NULL) {
|
||||
event_base_free(eb_);
|
||||
throw TException("evhttp_new failed");
|
||||
}
|
||||
|
||||
// Bind to port.
|
||||
int ret = evhttp_bind_socket(eh_, NULL, port);
|
||||
if (ret < 0) {
|
||||
evhttp_free(eh_);
|
||||
event_base_free(eb_);
|
||||
throw TException("evhttp_bind_socket failed");
|
||||
}
|
||||
|
||||
// Register a handler. If you use the other constructor,
|
||||
// you will want to do this yourself.
|
||||
// Don't forget to unregister before destorying this TEvhttpServer.
|
||||
evhttp_set_cb(eh_, "/", request, (void*)this);
|
||||
}
|
||||
|
||||
|
||||
TEvhttpServer::~TEvhttpServer() {
|
||||
if (eh_ != NULL) {
|
||||
evhttp_free(eh_);
|
||||
}
|
||||
if (eb_ != NULL) {
|
||||
event_base_free(eb_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int TEvhttpServer::serve() {
|
||||
if (eb_ == NULL) {
|
||||
throw TException("Unexpected call to TEvhttpServer::serve");
|
||||
}
|
||||
return event_base_dispatch(eb_);
|
||||
}
|
||||
|
||||
|
||||
TEvhttpServer::RequestContext::RequestContext(struct evhttp_request* req) : req(req)
|
||||
, ibuf(new TMemoryBuffer(EVBUFFER_DATA(req->input_buffer), EVBUFFER_LENGTH(req->input_buffer)))
|
||||
, obuf(new TMemoryBuffer())
|
||||
{}
|
||||
|
||||
|
||||
void TEvhttpServer::request(struct evhttp_request* req, void* self) {
|
||||
try {
|
||||
static_cast<TEvhttpServer*>(self)->process(req);
|
||||
} catch(std::exception& e) {
|
||||
evhttp_send_reply(req, HTTP_INTERNAL, e.what(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TEvhttpServer::process(struct evhttp_request* req) {
|
||||
RequestContext* ctx = new RequestContext(req);
|
||||
return processor_->process(
|
||||
std::tr1::bind(
|
||||
&TEvhttpServer::complete,
|
||||
this,
|
||||
ctx,
|
||||
std::tr1::placeholders::_1),
|
||||
ctx->ibuf,
|
||||
ctx->obuf);
|
||||
}
|
||||
|
||||
|
||||
void TEvhttpServer::complete(RequestContext* ctx, bool success) {
|
||||
(void) success;
|
||||
std::auto_ptr<RequestContext> ptr(ctx);
|
||||
|
||||
int code = success ? 200 : 400;
|
||||
const char* reason = success ? "OK" : "Bad Request";
|
||||
|
||||
int rv = evhttp_add_header(ctx->req->output_headers, "Content-Type", "application/x-thrift");
|
||||
if (rv != 0) {
|
||||
// TODO: Log an error.
|
||||
std::cerr << "evhttp_add_header failed " << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
}
|
||||
|
||||
struct evbuffer* buf = evbuffer_new();
|
||||
if (buf == NULL) {
|
||||
// TODO: Log an error.
|
||||
std::cerr << "evbuffer_new failed " << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
} else {
|
||||
uint8_t* obuf;
|
||||
uint32_t sz;
|
||||
ctx->obuf->getBuffer(&obuf, &sz);
|
||||
int ret = evbuffer_add(buf, obuf, sz);
|
||||
if (ret != 0) {
|
||||
// TODO: Log an error.
|
||||
std::cerr << "evhttp_add failed with " << ret << " " << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
evhttp_send_reply(ctx->req, code, reason, buf);
|
||||
if (buf != NULL) {
|
||||
evbuffer_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct event_base* TEvhttpServer::getEventBase() {
|
||||
return eb_;
|
||||
}
|
||||
|
||||
|
||||
}}} // apache::thrift::async
|
71
nativeLib/org.apache.thrift/include/async/TEvhttpServer.h
Normal file
71
nativeLib/org.apache.thrift/include/async/TEvhttpServer.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_TEVHTTP_SERVER_H_
|
||||
#define _THRIFT_TEVHTTP_SERVER_H_ 1
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
struct event_base;
|
||||
struct evhttp;
|
||||
struct evhttp_request;
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
class TAsyncBufferProcessor;
|
||||
|
||||
class TEvhttpServer {
|
||||
public:
|
||||
/**
|
||||
* Create a TEvhttpServer for use with an external evhttp instance.
|
||||
* Must be manually installed with evhttp_set_cb, using
|
||||
* TEvhttpServer::request as the callback and the
|
||||
* address of the server as the extra arg.
|
||||
* Do not call "serve" on this server.
|
||||
*/
|
||||
TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor);
|
||||
|
||||
/**
|
||||
* Create a TEvhttpServer with an embedded event_base and evhttp,
|
||||
* listening on port and responding on the endpoint "/".
|
||||
* Call "serve" on this server to serve forever.
|
||||
*/
|
||||
TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor, int port);
|
||||
|
||||
~TEvhttpServer();
|
||||
|
||||
static void request(struct evhttp_request* req, void* self);
|
||||
int serve();
|
||||
|
||||
struct event_base* getEventBase();
|
||||
|
||||
private:
|
||||
struct RequestContext;
|
||||
|
||||
void process(struct evhttp_request* req);
|
||||
void complete(RequestContext* ctx, bool success);
|
||||
|
||||
boost::shared_ptr<TAsyncBufferProcessor> processor_;
|
||||
struct event_base* eb_;
|
||||
struct evhttp* eh_;
|
||||
};
|
||||
|
||||
}}} // apache::thrift::async
|
||||
|
||||
#endif // #ifndef _THRIFT_TEVHTTP_SERVER_H_
|
198
nativeLib/org.apache.thrift/include/concurrency/BoostMonitor.cpp
Normal file
198
nativeLib/org.apache.thrift/include/concurrency/BoostMonitor.cpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include "Monitor.h"
|
||||
#include "Exception.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
/**
|
||||
* Monitor implementation using the boost thread library
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class Monitor::Impl : public boost::condition_variable_any {
|
||||
|
||||
public:
|
||||
|
||||
Impl()
|
||||
: ownedMutex_(new Mutex()),
|
||||
mutex_(NULL) {
|
||||
init(ownedMutex_.get());
|
||||
}
|
||||
|
||||
Impl(Mutex* mutex)
|
||||
: mutex_(NULL) {
|
||||
init(mutex);
|
||||
}
|
||||
|
||||
Impl(Monitor* monitor)
|
||||
: mutex_(NULL) {
|
||||
init(&(monitor->mutex()));
|
||||
}
|
||||
|
||||
Mutex& mutex() { return *mutex_; }
|
||||
void lock() { mutex().lock(); }
|
||||
void unlock() { mutex().unlock(); }
|
||||
|
||||
/**
|
||||
* Exception-throwing version of waitForTimeRelative(), called simply
|
||||
* wait(int64) for historical reasons. Timeout is in milliseconds.
|
||||
*
|
||||
* If the condition occurs, this function returns cleanly; on timeout or
|
||||
* error an exception is thrown.
|
||||
*/
|
||||
void wait(int64_t timeout_ms) {
|
||||
int result = waitForTimeRelative(timeout_ms);
|
||||
if (result == ETIMEDOUT) {
|
||||
throw TimedOutException();
|
||||
} else if (result != 0) {
|
||||
throw TException(
|
||||
"Monitor::wait() failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until the specified timeout in milliseconds for the condition to
|
||||
* occur, or waits forever if timeout_ms == 0.
|
||||
*
|
||||
* Returns 0 if condition occurs, ETIMEDOUT on timeout, or an error code.
|
||||
*/
|
||||
int waitForTimeRelative(int64_t timeout_ms) {
|
||||
if (timeout_ms == 0LL) {
|
||||
return waitForever();
|
||||
}
|
||||
|
||||
assert(mutex_);
|
||||
boost::timed_mutex* mutexImpl =
|
||||
reinterpret_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
|
||||
assert(mutexImpl);
|
||||
|
||||
boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
|
||||
int res = timed_wait(lock, boost::get_system_time()+boost::posix_time::milliseconds(timeout_ms)) ? 0 : ETIMEDOUT;
|
||||
lock.release();
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until the absolute time specified using struct timespec.
|
||||
* Returns 0 if condition occurs, ETIMEDOUT on timeout, or an error code.
|
||||
*/
|
||||
int waitForTime(const timespec* abstime) {
|
||||
assert(mutex_);
|
||||
boost::timed_mutex* mutexImpl =
|
||||
reinterpret_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
|
||||
assert(mutexImpl);
|
||||
|
||||
struct timespec currenttime;
|
||||
Util::toTimespec(currenttime, Util::currentTime());
|
||||
|
||||
long tv_sec = static_cast<long>(abstime->tv_sec - currenttime.tv_sec);
|
||||
long tv_nsec = static_cast<long>(abstime->tv_nsec - currenttime.tv_nsec);
|
||||
if(tv_sec < 0)
|
||||
tv_sec = 0;
|
||||
if(tv_nsec < 0)
|
||||
tv_nsec = 0;
|
||||
|
||||
boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
|
||||
int res = timed_wait(lock, boost::get_system_time() +
|
||||
boost::posix_time::seconds(tv_sec) +
|
||||
boost::posix_time::microseconds(tv_nsec / 1000)
|
||||
) ? 0 : ETIMEDOUT;
|
||||
lock.release();
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits forever until the condition occurs.
|
||||
* Returns 0 if condition occurs, or an error code otherwise.
|
||||
*/
|
||||
int waitForever() {
|
||||
assert(mutex_);
|
||||
boost::timed_mutex* mutexImpl =
|
||||
reinterpret_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
|
||||
assert(mutexImpl);
|
||||
|
||||
boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
|
||||
((boost::condition_variable_any*)this)->wait(lock);
|
||||
lock.release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void notify() {
|
||||
notify_one();
|
||||
}
|
||||
|
||||
void notifyAll() {
|
||||
notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void init(Mutex* mutex) {
|
||||
mutex_ = mutex;
|
||||
}
|
||||
|
||||
boost::scoped_ptr<Mutex> ownedMutex_;
|
||||
Mutex* mutex_;
|
||||
};
|
||||
|
||||
Monitor::Monitor() : impl_(new Monitor::Impl()) {}
|
||||
Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {}
|
||||
Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {}
|
||||
|
||||
Monitor::~Monitor() { delete impl_; }
|
||||
|
||||
Mutex& Monitor::mutex() const { return const_cast<Monitor::Impl*>(impl_)->mutex(); }
|
||||
|
||||
void Monitor::lock() const { const_cast<Monitor::Impl*>(impl_)->lock(); }
|
||||
|
||||
void Monitor::unlock() const { const_cast<Monitor::Impl*>(impl_)->unlock(); }
|
||||
|
||||
void Monitor::wait(int64_t timeout) const { const_cast<Monitor::Impl*>(impl_)->wait(timeout); }
|
||||
|
||||
int Monitor::waitForTime(const timespec* abstime) const {
|
||||
return const_cast<Monitor::Impl*>(impl_)->waitForTime(abstime);
|
||||
}
|
||||
|
||||
int Monitor::waitForTimeRelative(int64_t timeout_ms) const {
|
||||
return const_cast<Monitor::Impl*>(impl_)->waitForTimeRelative(timeout_ms);
|
||||
}
|
||||
|
||||
int Monitor::waitForever() const {
|
||||
return const_cast<Monitor::Impl*>(impl_)->waitForever();
|
||||
}
|
||||
|
||||
void Monitor::notify() const { const_cast<Monitor::Impl*>(impl_)->notify(); }
|
||||
|
||||
void Monitor::notifyAll() const { const_cast<Monitor::Impl*>(impl_)->notifyAll(); }
|
||||
|
||||
}}} // apache::thrift::concurrency
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include "Mutex.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
/**
|
||||
* Implementation of Mutex class using boost interprocess mutex
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class Mutex::impl : public boost::timed_mutex {
|
||||
};
|
||||
|
||||
Mutex::Mutex(Initializer init) : impl_(new Mutex::impl()) {}
|
||||
|
||||
void* Mutex::getUnderlyingImpl() const { return impl_.get(); }
|
||||
|
||||
void Mutex::lock() const { impl_->lock(); }
|
||||
|
||||
bool Mutex::trylock() const { return impl_->try_lock(); }
|
||||
|
||||
bool Mutex::timedlock(int64_t ms) const { return impl_->timed_lock(boost::get_system_time()+boost::posix_time::milliseconds(ms)); }
|
||||
|
||||
void Mutex::unlock() const { impl_->unlock(); }
|
||||
|
||||
void Mutex::DEFAULT_INITIALIZER(void* arg) {
|
||||
}
|
||||
|
||||
}}} // apache::thrift::concurrency
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include "BoostThreadFactory.h"
|
||||
#include "Exception.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
using boost::shared_ptr;
|
||||
using boost::weak_ptr;
|
||||
|
||||
/**
|
||||
* The boost thread class.
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class BoostThread: public Thread {
|
||||
public:
|
||||
|
||||
enum STATE {
|
||||
uninitialized,
|
||||
starting,
|
||||
started,
|
||||
stopping,
|
||||
stopped
|
||||
};
|
||||
|
||||
static void* threadMain(void* arg);
|
||||
|
||||
private:
|
||||
std::auto_ptr<boost::thread> thread_;
|
||||
STATE state_;
|
||||
weak_ptr<BoostThread> self_;
|
||||
bool detached_;
|
||||
|
||||
public:
|
||||
|
||||
BoostThread(bool detached, shared_ptr<Runnable> runnable) :
|
||||
state_(uninitialized),
|
||||
detached_(detached) {
|
||||
this->Thread::runnable(runnable);
|
||||
}
|
||||
|
||||
~BoostThread() {
|
||||
if(!detached_) {
|
||||
try {
|
||||
join();
|
||||
} catch(...) {
|
||||
// We're really hosed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void start() {
|
||||
if (state_ != uninitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create reference
|
||||
shared_ptr<BoostThread>* selfRef = new shared_ptr<BoostThread>();
|
||||
*selfRef = self_.lock();
|
||||
|
||||
state_ = starting;
|
||||
|
||||
thread_ = std::auto_ptr<boost::thread>(new boost::thread(boost::bind(threadMain, (void*)selfRef)));
|
||||
|
||||
if(detached_)
|
||||
thread_->detach();
|
||||
}
|
||||
|
||||
void join() {
|
||||
if (!detached_ && state_ != uninitialized) {
|
||||
thread_->join();
|
||||
}
|
||||
}
|
||||
|
||||
Thread::id_t getId() {
|
||||
return thread_.get() ? thread_->get_id() : boost::thread::id();
|
||||
}
|
||||
|
||||
shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
|
||||
|
||||
void runnable(shared_ptr<Runnable> value) { Thread::runnable(value); }
|
||||
|
||||
void weakRef(shared_ptr<BoostThread> self) {
|
||||
assert(self.get() == this);
|
||||
self_ = weak_ptr<BoostThread>(self);
|
||||
}
|
||||
};
|
||||
|
||||
void* BoostThread::threadMain(void* arg) {
|
||||
shared_ptr<BoostThread> thread = *(shared_ptr<BoostThread>*)arg;
|
||||
delete reinterpret_cast<shared_ptr<BoostThread>*>(arg);
|
||||
|
||||
if (thread == NULL) {
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
if (thread->state_ != starting) {
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
thread->state_ = started;
|
||||
thread->runnable()->run();
|
||||
|
||||
if (thread->state_ != stopping && thread->state_ != stopped) {
|
||||
thread->state_ = stopping;
|
||||
}
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* POSIX Thread factory implementation
|
||||
*/
|
||||
class BoostThreadFactory::Impl {
|
||||
|
||||
private:
|
||||
bool detached_;
|
||||
|
||||
public:
|
||||
|
||||
Impl(bool detached) :
|
||||
detached_(detached) {}
|
||||
|
||||
/**
|
||||
* Creates a new POSIX thread to run the runnable object
|
||||
*
|
||||
* @param runnable A runnable object
|
||||
*/
|
||||
shared_ptr<Thread> newThread(shared_ptr<Runnable> runnable) const {
|
||||
shared_ptr<BoostThread> result = shared_ptr<BoostThread>(new BoostThread(detached_, runnable));
|
||||
result->weakRef(result);
|
||||
runnable->thread(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool isDetached() const { return detached_; }
|
||||
|
||||
void setDetached(bool value) { detached_ = value; }
|
||||
|
||||
Thread::id_t getCurrentThreadId() const {
|
||||
return boost::this_thread::get_id();
|
||||
}
|
||||
};
|
||||
|
||||
BoostThreadFactory::BoostThreadFactory(bool detached) :
|
||||
impl_(new BoostThreadFactory::Impl(detached)) {}
|
||||
|
||||
shared_ptr<Thread> BoostThreadFactory::newThread(shared_ptr<Runnable> runnable) const { return impl_->newThread(runnable); }
|
||||
|
||||
bool BoostThreadFactory::isDetached() const { return impl_->isDetached(); }
|
||||
|
||||
void BoostThreadFactory::setDetached(bool value) { impl_->setDetached(value); }
|
||||
|
||||
Thread::id_t BoostThreadFactory::getCurrentThreadId() const { return impl_->getCurrentThreadId(); }
|
||||
|
||||
}}} // apache::thrift::concurrency
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_
|
||||
#define _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_ 1
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
/**
|
||||
* A thread factory to create posix threads
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class BoostThreadFactory : public ThreadFactory {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Boost thread factory. All threads created by a factory are reference-counted
|
||||
* via boost::shared_ptr and boost::weak_ptr. The factory guarantees that threads and
|
||||
* the Runnable tasks they host will be properly cleaned up once the last strong reference
|
||||
* to both is given up.
|
||||
*
|
||||
* Threads are created with the specified boost policy, priority, stack-size. A detachable thread is not
|
||||
* joinable.
|
||||
*
|
||||
* By default threads are not joinable.
|
||||
*/
|
||||
|
||||
BoostThreadFactory(bool detached=true);
|
||||
|
||||
// From ThreadFactory;
|
||||
boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const;
|
||||
|
||||
// From ThreadFactory;
|
||||
Thread::id_t getCurrentThreadId() const;
|
||||
|
||||
/**
|
||||
* Sets detached mode of threads
|
||||
*/
|
||||
virtual void setDetached(bool detached);
|
||||
|
||||
/**
|
||||
* Gets current detached mode
|
||||
*/
|
||||
virtual bool isDetached() const;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
boost::shared_ptr<Impl> impl_;
|
||||
};
|
||||
|
||||
}}} // apache::thrift::concurrency
|
||||
|
||||
#endif // #ifndef _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_
|
|
@ -21,7 +21,7 @@
|
|||
#define _THRIFT_CONCURRENCY_EXCEPTION_H_ 1
|
||||
|
||||
#include <exception>
|
||||
#include <Thrift.h>
|
||||
#include <thrift/Thrift.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
|
@ -31,7 +31,11 @@ class UncancellableTaskException : public apache::thrift::TException {};
|
|||
|
||||
class InvalidArgumentException : public apache::thrift::TException {};
|
||||
|
||||
class IllegalStateException : public apache::thrift::TException {};
|
||||
class IllegalStateException : public apache::thrift::TException {
|
||||
public:
|
||||
IllegalStateException() {}
|
||||
IllegalStateException(const std::string& message) : TException(message) {}
|
||||
};
|
||||
|
||||
class TimedOutException : public apache::thrift::TException {
|
||||
public:
|
||||
|
|
|
@ -34,16 +34,15 @@ namespace apache { namespace thrift { namespace concurrency {
|
|||
* void* my_thread_main(void* arg);
|
||||
* shared_ptr<ThreadFactory> factory = ...;
|
||||
* // To create a thread that executes my_thread_main once:
|
||||
* shared_ptr<Thread> thread =
|
||||
* factory->newThread(shared_ptr<FunctionRunner>(
|
||||
* new FunctionRunner(my_thread_main, some_argument)));
|
||||
* shared_ptr<Thread> thread = factory->newThread(
|
||||
* FunctionRunner::create(my_thread_main, some_argument));
|
||||
* thread->start();
|
||||
*
|
||||
* bool A::foo();
|
||||
* A* a = new A();
|
||||
* // To create a thread that executes a.foo() every 100 milliseconds:
|
||||
* factory->newThread(shared_ptr<FunctionRunner>(
|
||||
* new FunctionRunner(std::tr1::bind(&A::foo, a), 100)))->start();
|
||||
* factory->newThread(FunctionRunner::create(
|
||||
* std::tr1::bind(&A::foo, a), 100))->start();
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -56,6 +55,20 @@ class FunctionRunner : public Runnable {
|
|||
|
||||
typedef std::tr1::function<bool()> BoolFunc;
|
||||
|
||||
/**
|
||||
* Syntactic sugar to make it easier to create new FunctionRunner
|
||||
* objects wrapped in shared_ptr.
|
||||
*/
|
||||
static boost::shared_ptr<FunctionRunner> create(const VoidFunc& cob) {
|
||||
return boost::shared_ptr<FunctionRunner>(new FunctionRunner(cob));
|
||||
}
|
||||
|
||||
static boost::shared_ptr<FunctionRunner> create(PthreadFuncPtr func,
|
||||
void* arg) {
|
||||
return boost::shared_ptr<FunctionRunner>(new FunctionRunner(func, arg));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a 'pthread_create' style callback, this FunctionRunner will
|
||||
* execute the given callback. Note that the 'void*' return value is ignored.
|
||||
|
|
208
nativeLib/org.apache.thrift/include/concurrency/Monitor.cpp
Normal file
208
nativeLib/org.apache.thrift/include/concurrency/Monitor.cpp
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "Monitor.h"
|
||||
#include "Exception.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
using boost::scoped_ptr;
|
||||
|
||||
/**
|
||||
* Monitor implementation using the POSIX pthread library
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class Monitor::Impl {
|
||||
|
||||
public:
|
||||
|
||||
Impl()
|
||||
: ownedMutex_(new Mutex()),
|
||||
mutex_(NULL),
|
||||
condInitialized_(false) {
|
||||
init(ownedMutex_.get());
|
||||
}
|
||||
|
||||
Impl(Mutex* mutex)
|
||||
: mutex_(NULL),
|
||||
condInitialized_(false) {
|
||||
init(mutex);
|
||||
}
|
||||
|
||||
Impl(Monitor* monitor)
|
||||
: mutex_(NULL),
|
||||
condInitialized_(false) {
|
||||
init(&(monitor->mutex()));
|
||||
}
|
||||
|
||||
~Impl() { cleanup(); }
|
||||
|
||||
Mutex& mutex() { return *mutex_; }
|
||||
void lock() { mutex().lock(); }
|
||||
void unlock() { mutex().unlock(); }
|
||||
|
||||
/**
|
||||
* Exception-throwing version of waitForTimeRelative(), called simply
|
||||
* wait(int64) for historical reasons. Timeout is in milliseconds.
|
||||
*
|
||||
* If the condition occurs, this function returns cleanly; on timeout or
|
||||
* error an exception is thrown.
|
||||
*/
|
||||
void wait(int64_t timeout_ms) const {
|
||||
int result = waitForTimeRelative(timeout_ms);
|
||||
if (result == ETIMEDOUT) {
|
||||
// pthread_cond_timedwait has been observed to return early on
|
||||
// various platforms, so comment out this assert.
|
||||
//assert(Util::currentTime() >= (now + timeout));
|
||||
throw TimedOutException();
|
||||
} else if (result != 0) {
|
||||
throw TException(
|
||||
"pthread_cond_wait() or pthread_cond_timedwait() failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until the specified timeout in milliseconds for the condition to
|
||||
* occur, or waits forever if timeout_ms == 0.
|
||||
*
|
||||
* Returns 0 if condition occurs, ETIMEDOUT on timeout, or an error code.
|
||||
*/
|
||||
int waitForTimeRelative(int64_t timeout_ms) const {
|
||||
if (timeout_ms == 0LL) {
|
||||
return waitForever();
|
||||
}
|
||||
|
||||
struct timespec abstime;
|
||||
Util::toTimespec(abstime, Util::currentTime() + timeout_ms);
|
||||
return waitForTime(&abstime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until the absolute time specified using struct timespec.
|
||||
* Returns 0 if condition occurs, ETIMEDOUT on timeout, or an error code.
|
||||
*/
|
||||
int waitForTime(const timespec* abstime) const {
|
||||
assert(mutex_);
|
||||
pthread_mutex_t* mutexImpl =
|
||||
reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
|
||||
assert(mutexImpl);
|
||||
|
||||
// XXX Need to assert that caller owns mutex
|
||||
return pthread_cond_timedwait(&pthread_cond_,
|
||||
mutexImpl,
|
||||
abstime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits forever until the condition occurs.
|
||||
* Returns 0 if condition occurs, or an error code otherwise.
|
||||
*/
|
||||
int waitForever() const {
|
||||
assert(mutex_);
|
||||
pthread_mutex_t* mutexImpl =
|
||||
reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
|
||||
assert(mutexImpl);
|
||||
return pthread_cond_wait(&pthread_cond_, mutexImpl);
|
||||
}
|
||||
|
||||
|
||||
void notify() {
|
||||
// XXX Need to assert that caller owns mutex
|
||||
int iret = pthread_cond_signal(&pthread_cond_);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
void notifyAll() {
|
||||
// XXX Need to assert that caller owns mutex
|
||||
int iret = pthread_cond_broadcast(&pthread_cond_);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void init(Mutex* mutex) {
|
||||
mutex_ = mutex;
|
||||
|
||||
if (pthread_cond_init(&pthread_cond_, NULL) == 0) {
|
||||
condInitialized_ = true;
|
||||
}
|
||||
|
||||
if (!condInitialized_) {
|
||||
cleanup();
|
||||
throw SystemResourceException();
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
if (condInitialized_) {
|
||||
condInitialized_ = false;
|
||||
int iret = pthread_cond_destroy(&pthread_cond_);
|
||||
assert(iret == 0);
|
||||
}
|
||||
}
|
||||
|
||||
scoped_ptr<Mutex> ownedMutex_;
|
||||
Mutex* mutex_;
|
||||
|
||||
mutable pthread_cond_t pthread_cond_;
|
||||
mutable bool condInitialized_;
|
||||
};
|
||||
|
||||
Monitor::Monitor() : impl_(new Monitor::Impl()) {}
|
||||
Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {}
|
||||
Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {}
|
||||
|
||||
Monitor::~Monitor() { delete impl_; }
|
||||
|
||||
Mutex& Monitor::mutex() const { return impl_->mutex(); }
|
||||
|
||||
void Monitor::lock() const { impl_->lock(); }
|
||||
|
||||
void Monitor::unlock() const { impl_->unlock(); }
|
||||
|
||||
void Monitor::wait(int64_t timeout) const { impl_->wait(timeout); }
|
||||
|
||||
int Monitor::waitForTime(const timespec* abstime) const {
|
||||
return impl_->waitForTime(abstime);
|
||||
}
|
||||
|
||||
int Monitor::waitForTimeRelative(int64_t timeout_ms) const {
|
||||
return impl_->waitForTimeRelative(timeout_ms);
|
||||
}
|
||||
|
||||
int Monitor::waitForever() const {
|
||||
return impl_->waitForever();
|
||||
}
|
||||
|
||||
void Monitor::notify() const { impl_->notify(); }
|
||||
|
||||
void Monitor::notifyAll() const { impl_->notifyAll(); }
|
||||
|
||||
}}} // apache::thrift::concurrency
|
|
@ -66,10 +66,40 @@ class Monitor : boost::noncopyable {
|
|||
|
||||
virtual void unlock() const;
|
||||
|
||||
virtual void wait(int64_t timeout=0LL) const;
|
||||
/**
|
||||
* Waits a maximum of the specified timeout in milliseconds for the condition
|
||||
* to occur, or waits forever if timeout_ms == 0.
|
||||
*
|
||||
* Returns 0 if condition occurs, ETIMEDOUT on timeout, or an error code.
|
||||
*/
|
||||
int waitForTimeRelative(int64_t timeout_ms) const;
|
||||
|
||||
/**
|
||||
* Waits until the absolute time specified using struct timespec.
|
||||
* Returns 0 if condition occurs, ETIMEDOUT on timeout, or an error code.
|
||||
*/
|
||||
int waitForTime(const timespec* abstime) const;
|
||||
|
||||
/**
|
||||
* Waits forever until the condition occurs.
|
||||
* Returns 0 if condition occurs, or an error code otherwise.
|
||||
*/
|
||||
int waitForever() const;
|
||||
|
||||
/**
|
||||
* Exception-throwing version of waitForTimeRelative(), called simply
|
||||
* wait(int64) for historical reasons. Timeout is in milliseconds.
|
||||
*
|
||||
* If the condition occurs, this function returns cleanly; on timeout or
|
||||
* error an exception is thrown.
|
||||
*/
|
||||
void wait(int64_t timeout_ms = 0LL) const;
|
||||
|
||||
|
||||
/** Wakes up one thread waiting on this monitor. */
|
||||
virtual void notify() const;
|
||||
|
||||
/** Wakes up all waiting threads on this monitor. */
|
||||
virtual void notifyAll() const;
|
||||
|
||||
private:
|
||||
|
|
348
nativeLib/org.apache.thrift/include/concurrency/Mutex.cpp
Normal file
348
nativeLib/org.apache.thrift/include/concurrency/Mutex.cpp
Normal file
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include "Mutex.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_PTHREAD_H
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
|
||||
using boost::shared_ptr;
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
#ifndef THRIFT_NO_CONTENTION_PROFILING
|
||||
|
||||
static sig_atomic_t mutexProfilingSampleRate = 0;
|
||||
static MutexWaitCallback mutexProfilingCallback = 0;
|
||||
|
||||
volatile static sig_atomic_t mutexProfilingCounter = 0;
|
||||
|
||||
void enableMutexProfiling(int32_t profilingSampleRate,
|
||||
MutexWaitCallback callback) {
|
||||
mutexProfilingSampleRate = profilingSampleRate;
|
||||
mutexProfilingCallback = callback;
|
||||
}
|
||||
|
||||
#define PROFILE_MUTEX_START_LOCK() \
|
||||
int64_t _lock_startTime = maybeGetProfilingStartTime();
|
||||
|
||||
#define PROFILE_MUTEX_NOT_LOCKED() \
|
||||
do { \
|
||||
if (_lock_startTime > 0) { \
|
||||
int64_t endTime = Util::currentTimeUsec(); \
|
||||
(*mutexProfilingCallback)(this, endTime - _lock_startTime); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PROFILE_MUTEX_LOCKED() \
|
||||
do { \
|
||||
profileTime_ = _lock_startTime; \
|
||||
if (profileTime_ > 0) { \
|
||||
profileTime_ = Util::currentTimeUsec() - profileTime_; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PROFILE_MUTEX_START_UNLOCK() \
|
||||
int64_t _temp_profileTime = profileTime_; \
|
||||
profileTime_ = 0;
|
||||
|
||||
#define PROFILE_MUTEX_UNLOCKED() \
|
||||
do { \
|
||||
if (_temp_profileTime > 0) { \
|
||||
(*mutexProfilingCallback)(this, _temp_profileTime); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline int64_t maybeGetProfilingStartTime() {
|
||||
if (mutexProfilingSampleRate && mutexProfilingCallback) {
|
||||
// This block is unsynchronized, but should produce a reasonable sampling
|
||||
// rate on most architectures. The main race conditions are the gap
|
||||
// between the decrement and the test, the non-atomicity of decrement, and
|
||||
// potential caching of different values at different CPUs.
|
||||
//
|
||||
// - if two decrements race, the likeliest result is that the counter
|
||||
// decrements slowly (perhaps much more slowly) than intended.
|
||||
//
|
||||
// - many threads could potentially decrement before resetting the counter
|
||||
// to its large value, causing each additional incoming thread to
|
||||
// profile every call. This situation is unlikely to persist for long
|
||||
// as the critical gap is quite short, but profiling could be bursty.
|
||||
sig_atomic_t localValue = --mutexProfilingCounter;
|
||||
if (localValue <= 0) {
|
||||
mutexProfilingCounter = mutexProfilingSampleRate;
|
||||
return Util::currentTimeUsec();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
# define PROFILE_MUTEX_START_LOCK()
|
||||
# define PROFILE_MUTEX_NOT_LOCKED()
|
||||
# define PROFILE_MUTEX_LOCKED()
|
||||
# define PROFILE_MUTEX_START_UNLOCK()
|
||||
# define PROFILE_MUTEX_UNLOCKED()
|
||||
#endif // THRIFT_NO_CONTENTION_PROFILING
|
||||
|
||||
/**
|
||||
* Implementation of Mutex class using POSIX mutex
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class Mutex::impl {
|
||||
public:
|
||||
impl(Initializer init) : initialized_(false) {
|
||||
#ifndef THRIFT_NO_CONTENTION_PROFILING
|
||||
profileTime_ = 0;
|
||||
#endif
|
||||
init(&pthread_mutex_);
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
~impl() {
|
||||
if (initialized_) {
|
||||
initialized_ = false;
|
||||
int ret = pthread_mutex_destroy(&pthread_mutex_);
|
||||
assert(ret == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void lock() const {
|
||||
PROFILE_MUTEX_START_LOCK();
|
||||
pthread_mutex_lock(&pthread_mutex_);
|
||||
PROFILE_MUTEX_LOCKED();
|
||||
}
|
||||
|
||||
bool trylock() const { return (0 == pthread_mutex_trylock(&pthread_mutex_)); }
|
||||
|
||||
bool timedlock(int64_t milliseconds) const {
|
||||
#if defined(_POSIX_TIMEOUTS) && _POSIX_TIMEOUTS >= 200112L
|
||||
PROFILE_MUTEX_START_LOCK();
|
||||
|
||||
struct timespec ts;
|
||||
Util::toTimespec(ts, milliseconds + Util::currentTime());
|
||||
int ret = pthread_mutex_timedlock(&pthread_mutex_, &ts);
|
||||
if (ret == 0) {
|
||||
PROFILE_MUTEX_LOCKED();
|
||||
return true;
|
||||
}
|
||||
|
||||
PROFILE_MUTEX_NOT_LOCKED();
|
||||
return false;
|
||||
#else
|
||||
/* Otherwise follow solution used by Mono for Android */
|
||||
struct timespec sleepytime, now, to;
|
||||
|
||||
/* This is just to avoid a completely busy wait */
|
||||
sleepytime.tv_sec = 0;
|
||||
sleepytime.tv_nsec = 10000000L; /* 10ms */
|
||||
|
||||
Util::toTimespec(to, milliseconds + Util::currentTime());
|
||||
|
||||
while ((trylock()) == false) {
|
||||
Util::toTimespec(now, Util::currentTime());
|
||||
if (now.tv_sec >= to.tv_sec && now.tv_nsec >= to.tv_nsec) {
|
||||
return false;
|
||||
}
|
||||
nanosleep(&sleepytime, NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void unlock() const {
|
||||
PROFILE_MUTEX_START_UNLOCK();
|
||||
pthread_mutex_unlock(&pthread_mutex_);
|
||||
PROFILE_MUTEX_UNLOCKED();
|
||||
}
|
||||
|
||||
void* getUnderlyingImpl() const { return (void*) &pthread_mutex_; }
|
||||
|
||||
private:
|
||||
mutable pthread_mutex_t pthread_mutex_;
|
||||
mutable bool initialized_;
|
||||
#ifndef THRIFT_NO_CONTENTION_PROFILING
|
||||
mutable int64_t profileTime_;
|
||||
#endif
|
||||
};
|
||||
|
||||
Mutex::Mutex(Initializer init) : impl_(new Mutex::impl(init)) {}
|
||||
|
||||
void* Mutex::getUnderlyingImpl() const { return impl_->getUnderlyingImpl(); }
|
||||
|
||||
void Mutex::lock() const { impl_->lock(); }
|
||||
|
||||
bool Mutex::trylock() const { return impl_->trylock(); }
|
||||
|
||||
bool Mutex::timedlock(int64_t ms) const { return impl_->timedlock(ms); }
|
||||
|
||||
void Mutex::unlock() const { impl_->unlock(); }
|
||||
|
||||
void Mutex::DEFAULT_INITIALIZER(void* arg) {
|
||||
pthread_mutex_t* pthread_mutex = (pthread_mutex_t*)arg;
|
||||
int ret = pthread_mutex_init(pthread_mutex, NULL);
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
#if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) || defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
|
||||
static void init_with_kind(pthread_mutex_t* mutex, int kind) {
|
||||
pthread_mutexattr_t mutexattr;
|
||||
int ret = pthread_mutexattr_init(&mutexattr);
|
||||
assert(ret == 0);
|
||||
|
||||
// Apparently, this can fail. Should we really be aborting?
|
||||
ret = pthread_mutexattr_settype(&mutexattr, kind);
|
||||
assert(ret == 0);
|
||||
|
||||
ret = pthread_mutex_init(mutex, &mutexattr);
|
||||
assert(ret == 0);
|
||||
|
||||
ret = pthread_mutexattr_destroy(&mutexattr);
|
||||
assert(ret == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
void Mutex::ADAPTIVE_INITIALIZER(void* arg) {
|
||||
// From mysql source: mysys/my_thr_init.c
|
||||
// Set mutex type to "fast" a.k.a "adaptive"
|
||||
//
|
||||
// In this case the thread may steal the mutex from some other thread
|
||||
// that is waiting for the same mutex. This will save us some
|
||||
// context switches but may cause a thread to 'starve forever' while
|
||||
// waiting for the mutex (not likely if the code within the mutex is
|
||||
// short).
|
||||
init_with_kind((pthread_mutex_t*)arg, PTHREAD_MUTEX_ADAPTIVE_NP);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
|
||||
void Mutex::RECURSIVE_INITIALIZER(void* arg) {
|
||||
init_with_kind((pthread_mutex_t*)arg, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of ReadWriteMutex class using POSIX rw lock
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class ReadWriteMutex::impl {
|
||||
public:
|
||||
impl() : initialized_(false) {
|
||||
#ifndef THRIFT_NO_CONTENTION_PROFILING
|
||||
profileTime_ = 0;
|
||||
#endif
|
||||
int ret = pthread_rwlock_init(&rw_lock_, NULL);
|
||||
assert(ret == 0);
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
~impl() {
|
||||
if(initialized_) {
|
||||
initialized_ = false;
|
||||
int ret = pthread_rwlock_destroy(&rw_lock_);
|
||||
assert(ret == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void acquireRead() const {
|
||||
PROFILE_MUTEX_START_LOCK();
|
||||
pthread_rwlock_rdlock(&rw_lock_);
|
||||
PROFILE_MUTEX_NOT_LOCKED(); // not exclusive, so use not-locked path
|
||||
}
|
||||
|
||||
void acquireWrite() const {
|
||||
PROFILE_MUTEX_START_LOCK();
|
||||
pthread_rwlock_wrlock(&rw_lock_);
|
||||
PROFILE_MUTEX_LOCKED();
|
||||
}
|
||||
|
||||
bool attemptRead() const { return !pthread_rwlock_tryrdlock(&rw_lock_); }
|
||||
|
||||
bool attemptWrite() const { return !pthread_rwlock_trywrlock(&rw_lock_); }
|
||||
|
||||
void release() const {
|
||||
PROFILE_MUTEX_START_UNLOCK();
|
||||
pthread_rwlock_unlock(&rw_lock_);
|
||||
PROFILE_MUTEX_UNLOCKED();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable pthread_rwlock_t rw_lock_;
|
||||
mutable bool initialized_;
|
||||
#ifndef THRIFT_NO_CONTENTION_PROFILING
|
||||
mutable int64_t profileTime_;
|
||||
#endif
|
||||
};
|
||||
|
||||
ReadWriteMutex::ReadWriteMutex() : impl_(new ReadWriteMutex::impl()) {}
|
||||
|
||||
void ReadWriteMutex::acquireRead() const { impl_->acquireRead(); }
|
||||
|
||||
void ReadWriteMutex::acquireWrite() const { impl_->acquireWrite(); }
|
||||
|
||||
bool ReadWriteMutex::attemptRead() const { return impl_->attemptRead(); }
|
||||
|
||||
bool ReadWriteMutex::attemptWrite() const { return impl_->attemptWrite(); }
|
||||
|
||||
void ReadWriteMutex::release() const { impl_->release(); }
|
||||
|
||||
NoStarveReadWriteMutex::NoStarveReadWriteMutex() : writerWaiting_(false) {}
|
||||
|
||||
void NoStarveReadWriteMutex::acquireRead() const
|
||||
{
|
||||
if (writerWaiting_) {
|
||||
// writer is waiting, block on the writer's mutex until he's done with it
|
||||
mutex_.lock();
|
||||
mutex_.unlock();
|
||||
}
|
||||
|
||||
ReadWriteMutex::acquireRead();
|
||||
}
|
||||
|
||||
void NoStarveReadWriteMutex::acquireWrite() const
|
||||
{
|
||||
// if we can acquire the rwlock the easy way, we're done
|
||||
if (attemptWrite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// failed to get the rwlock, do it the hard way:
|
||||
// locking the mutex and setting writerWaiting will cause all new readers to
|
||||
// block on the mutex rather than on the rwlock.
|
||||
mutex_.lock();
|
||||
writerWaiting_ = true;
|
||||
ReadWriteMutex::acquireWrite();
|
||||
writerWaiting_ = false;
|
||||
mutex_.unlock();
|
||||
}
|
||||
|
||||
}}} // apache::thrift::concurrency
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
#define _THRIFT_CONCURRENCY_MUTEX_H_ 1
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
|
@ -100,7 +101,26 @@ private:
|
|||
boost::shared_ptr<impl> impl_;
|
||||
};
|
||||
|
||||
class Guard {
|
||||
/**
|
||||
* A ReadWriteMutex that guarantees writers will not be starved by readers:
|
||||
* When a writer attempts to acquire the mutex, all new readers will be
|
||||
* blocked from acquiring the mutex until the writer has acquired and
|
||||
* released it. In some operating systems, this may already be guaranteed
|
||||
* by a regular ReadWriteMutex.
|
||||
*/
|
||||
class NoStarveReadWriteMutex : public ReadWriteMutex {
|
||||
public:
|
||||
NoStarveReadWriteMutex();
|
||||
|
||||
virtual void acquireRead() const;
|
||||
virtual void acquireWrite() const;
|
||||
|
||||
private:
|
||||
Mutex mutex_;
|
||||
mutable volatile bool writerWaiting_;
|
||||
};
|
||||
|
||||
class Guard : boost::noncopyable {
|
||||
public:
|
||||
Guard(const Mutex& value, int64_t timeout = 0) : mutex_(&value) {
|
||||
if (timeout == 0) {
|
||||
|
@ -133,11 +153,11 @@ class Guard {
|
|||
// as to whether we're doing acquireRead() or acquireWrite().
|
||||
enum RWGuardType {
|
||||
RW_READ = 0,
|
||||
RW_WRITE = 1,
|
||||
RW_WRITE = 1
|
||||
};
|
||||
|
||||
|
||||
class RWGuard {
|
||||
class RWGuard : boost::noncopyable {
|
||||
public:
|
||||
RWGuard(const ReadWriteMutex& value, bool write = false)
|
||||
: rw_mutex_(value) {
|
||||
|
@ -166,7 +186,7 @@ class RWGuard {
|
|||
|
||||
// A little hack to prevent someone from trying to do "Guard(m);"
|
||||
// Such a use is invalid because the temporary Guard object is
|
||||
// destoryed at the end of the line, releasing the lock.
|
||||
// destroyed at the end of the line, releasing the lock.
|
||||
// Sorry for polluting the global namespace, but I think it's worth it.
|
||||
#define Guard(m) incorrect_use_of_Guard(m)
|
||||
#define RWGuard(m) incorrect_use_of_RWGuard(m)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_
|
||||
#define _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_ 1
|
||||
|
||||
#ifndef USE_BOOST_THREAD
|
||||
# include <thrift/concurrency/PosixThreadFactory.h>
|
||||
#else
|
||||
# include <thrift/concurrency/BoostThreadFactory.h>
|
||||
#endif
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
#ifndef USE_BOOST_THREAD
|
||||
typedef PosixThreadFactory PlatformThreadFactory;
|
||||
#else
|
||||
typedef BoostThreadFactory PlatformThreadFactory;
|
||||
#endif
|
||||
|
||||
}}} // apache::thrift::concurrency
|
||||
|
||||
#endif // #ifndef _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include "PosixThreadFactory.h"
|
||||
#include "Exception.h"
|
||||
|
||||
#if GOOGLE_PERFTOOLS_REGISTER_THREAD
|
||||
# include <google/profiler.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
using boost::shared_ptr;
|
||||
using boost::weak_ptr;
|
||||
|
||||
/**
|
||||
* The POSIX thread class.
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class PthreadThread: public Thread {
|
||||
public:
|
||||
|
||||
enum STATE {
|
||||
uninitialized,
|
||||
starting,
|
||||
started,
|
||||
stopping,
|
||||
stopped
|
||||
};
|
||||
|
||||
static const int MB = 1024 * 1024;
|
||||
|
||||
static void* threadMain(void* arg);
|
||||
|
||||
private:
|
||||
pthread_t pthread_;
|
||||
STATE state_;
|
||||
int policy_;
|
||||
int priority_;
|
||||
int stackSize_;
|
||||
weak_ptr<PthreadThread> self_;
|
||||
bool detached_;
|
||||
|
||||
public:
|
||||
|
||||
PthreadThread(int policy, int priority, int stackSize, bool detached, shared_ptr<Runnable> runnable) :
|
||||
|
||||
#ifndef _WIN32
|
||||
pthread_(0),
|
||||
#endif // _WIN32
|
||||
|
||||
state_(uninitialized),
|
||||
policy_(policy),
|
||||
priority_(priority),
|
||||
stackSize_(stackSize),
|
||||
detached_(detached) {
|
||||
|
||||
this->Thread::runnable(runnable);
|
||||
}
|
||||
|
||||
~PthreadThread() {
|
||||
/* Nothing references this thread, if is is not detached, do a join
|
||||
now, otherwise the thread-id and, possibly, other resources will
|
||||
be leaked. */
|
||||
if(!detached_) {
|
||||
try {
|
||||
join();
|
||||
} catch(...) {
|
||||
// We're really hosed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void start() {
|
||||
if (state_ != uninitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_attr_t thread_attr;
|
||||
if (pthread_attr_init(&thread_attr) != 0) {
|
||||
throw SystemResourceException("pthread_attr_init failed");
|
||||
}
|
||||
|
||||
if(pthread_attr_setdetachstate(&thread_attr,
|
||||
detached_ ?
|
||||
PTHREAD_CREATE_DETACHED :
|
||||
PTHREAD_CREATE_JOINABLE) != 0) {
|
||||
throw SystemResourceException("pthread_attr_setdetachstate failed");
|
||||
}
|
||||
|
||||
// Set thread stack size
|
||||
if (pthread_attr_setstacksize(&thread_attr, MB * stackSize_) != 0) {
|
||||
throw SystemResourceException("pthread_attr_setstacksize failed");
|
||||
}
|
||||
|
||||
// Set thread policy
|
||||
#ifdef _WIN32
|
||||
//WIN32 Pthread implementation doesn't seem to support sheduling policies other then PosixThreadFactory::OTHER - runtime error
|
||||
policy_ = PosixThreadFactory::OTHER;
|
||||
#endif
|
||||
|
||||
if (pthread_attr_setschedpolicy(&thread_attr, policy_) != 0) {
|
||||
throw SystemResourceException("pthread_attr_setschedpolicy failed");
|
||||
}
|
||||
|
||||
struct sched_param sched_param;
|
||||
sched_param.sched_priority = priority_;
|
||||
|
||||
// Set thread priority
|
||||
if (pthread_attr_setschedparam(&thread_attr, &sched_param) != 0) {
|
||||
throw SystemResourceException("pthread_attr_setschedparam failed");
|
||||
}
|
||||
|
||||
// Create reference
|
||||
shared_ptr<PthreadThread>* selfRef = new shared_ptr<PthreadThread>();
|
||||
*selfRef = self_.lock();
|
||||
|
||||
state_ = starting;
|
||||
|
||||
if (pthread_create(&pthread_, &thread_attr, threadMain, (void*)selfRef) != 0) {
|
||||
throw SystemResourceException("pthread_create failed");
|
||||
}
|
||||
}
|
||||
|
||||
void join() {
|
||||
if (!detached_ && state_ != uninitialized) {
|
||||
void* ignore;
|
||||
/* XXX
|
||||
If join fails it is most likely due to the fact
|
||||
that the last reference was the thread itself and cannot
|
||||
join. This results in leaked threads and will eventually
|
||||
cause the process to run out of thread resources.
|
||||
We're beyond the point of throwing an exception. Not clear how
|
||||
best to handle this. */
|
||||
int res = pthread_join(pthread_, &ignore);
|
||||
detached_ = (res == 0);
|
||||
if (res != 0) {
|
||||
GlobalOutput.printf("PthreadThread::join(): fail with code %d", res);
|
||||
}
|
||||
} else {
|
||||
GlobalOutput.printf("PthreadThread::join(): detached thread");
|
||||
}
|
||||
}
|
||||
|
||||
Thread::id_t getId() {
|
||||
|
||||
#ifndef _WIN32
|
||||
return (Thread::id_t)pthread_;
|
||||
#else
|
||||
return (Thread::id_t)pthread_.p;
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
|
||||
|
||||
void runnable(shared_ptr<Runnable> value) { Thread::runnable(value); }
|
||||
|
||||
void weakRef(shared_ptr<PthreadThread> self) {
|
||||
assert(self.get() == this);
|
||||
self_ = weak_ptr<PthreadThread>(self);
|
||||
}
|
||||
};
|
||||
|
||||
void* PthreadThread::threadMain(void* arg) {
|
||||
shared_ptr<PthreadThread> thread = *(shared_ptr<PthreadThread>*)arg;
|
||||
delete reinterpret_cast<shared_ptr<PthreadThread>*>(arg);
|
||||
|
||||
if (thread == NULL) {
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
if (thread->state_ != starting) {
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
#if GOOGLE_PERFTOOLS_REGISTER_THREAD
|
||||
ProfilerRegisterThread();
|
||||
#endif
|
||||
|
||||
thread->state_ = started;
|
||||
thread->runnable()->run();
|
||||
if (thread->state_ != stopping && thread->state_ != stopped) {
|
||||
thread->state_ = stopping;
|
||||
}
|
||||
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* POSIX Thread factory implementation
|
||||
*/
|
||||
class PosixThreadFactory::Impl {
|
||||
|
||||
private:
|
||||
POLICY policy_;
|
||||
PRIORITY priority_;
|
||||
int stackSize_;
|
||||
bool detached_;
|
||||
|
||||
/**
|
||||
* Converts generic posix thread schedule policy enums into pthread
|
||||
* API values.
|
||||
*/
|
||||
static int toPthreadPolicy(POLICY policy) {
|
||||
switch (policy) {
|
||||
case OTHER:
|
||||
return SCHED_OTHER;
|
||||
case FIFO:
|
||||
return SCHED_FIFO;
|
||||
case ROUND_ROBIN:
|
||||
return SCHED_RR;
|
||||
}
|
||||
return SCHED_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts relative thread priorities to absolute value based on posix
|
||||
* thread scheduler policy
|
||||
*
|
||||
* The idea is simply to divide up the priority range for the given policy
|
||||
* into the correpsonding relative priority level (lowest..highest) and
|
||||
* then pro-rate accordingly.
|
||||
*/
|
||||
static int toPthreadPriority(POLICY policy, PRIORITY priority) {
|
||||
int pthread_policy = toPthreadPolicy(policy);
|
||||
int min_priority = 0;
|
||||
int max_priority = 0;
|
||||
#ifdef HAVE_SCHED_GET_PRIORITY_MIN
|
||||
min_priority = sched_get_priority_min(pthread_policy);
|
||||
#endif
|
||||
#ifdef HAVE_SCHED_GET_PRIORITY_MAX
|
||||
max_priority = sched_get_priority_max(pthread_policy);
|
||||
#endif
|
||||
int quanta = (HIGHEST - LOWEST) + 1;
|
||||
float stepsperquanta = (float)(max_priority - min_priority) / quanta;
|
||||
|
||||
if (priority <= HIGHEST) {
|
||||
return (int)(min_priority + stepsperquanta * priority);
|
||||
} else {
|
||||
// should never get here for priority increments.
|
||||
assert(false);
|
||||
return (int)(min_priority + stepsperquanta * NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Impl(POLICY policy, PRIORITY priority, int stackSize, bool detached) :
|
||||
policy_(policy),
|
||||
priority_(priority),
|
||||
stackSize_(stackSize),
|
||||
detached_(detached) {}
|
||||
|
||||
/**
|
||||
* Creates a new POSIX thread to run the runnable object
|
||||
*
|
||||
* @param runnable A runnable object
|
||||
*/
|
||||
shared_ptr<Thread> newThread(shared_ptr<Runnable> runnable) const {
|
||||
shared_ptr<PthreadThread> result = shared_ptr<PthreadThread>(new PthreadThread(toPthreadPolicy(policy_), toPthreadPriority(policy_, priority_), stackSize_, detached_, runnable));
|
||||
result->weakRef(result);
|
||||
runnable->thread(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int getStackSize() const { return stackSize_; }
|
||||
|
||||
void setStackSize(int value) { stackSize_ = value; }
|
||||
|
||||
PRIORITY getPriority() const { return priority_; }
|
||||
|
||||
/**
|
||||
* Sets priority.
|
||||
*
|
||||
* XXX
|
||||
* Need to handle incremental priorities properly.
|
||||
*/
|
||||
void setPriority(PRIORITY value) { priority_ = value; }
|
||||
|
||||
bool isDetached() const { return detached_; }
|
||||
|
||||
void setDetached(bool value) { detached_ = value; }
|
||||
|
||||
Thread::id_t getCurrentThreadId() const {
|
||||
|
||||
#ifndef _WIN32
|
||||
return (Thread::id_t)pthread_self();
|
||||
#else
|
||||
return (Thread::id_t)pthread_self().p;
|
||||
#endif // _WIN32
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
PosixThreadFactory::PosixThreadFactory(POLICY policy, PRIORITY priority, int stackSize, bool detached) :
|
||||
impl_(new PosixThreadFactory::Impl(policy, priority, stackSize, detached)) {}
|
||||
|
||||
shared_ptr<Thread> PosixThreadFactory::newThread(shared_ptr<Runnable> runnable) const { return impl_->newThread(runnable); }
|
||||
|
||||
int PosixThreadFactory::getStackSize() const { return impl_->getStackSize(); }
|
||||
|
||||
void PosixThreadFactory::setStackSize(int value) { impl_->setStackSize(value); }
|
||||
|
||||
PosixThreadFactory::PRIORITY PosixThreadFactory::getPriority() const { return impl_->getPriority(); }
|
||||
|
||||
void PosixThreadFactory::setPriority(PosixThreadFactory::PRIORITY value) { impl_->setPriority(value); }
|
||||
|
||||
bool PosixThreadFactory::isDetached() const { return impl_->isDetached(); }
|
||||
|
||||
void PosixThreadFactory::setDetached(bool value) { impl_->setDetached(value); }
|
||||
|
||||
Thread::id_t PosixThreadFactory::getCurrentThreadId() const { return impl_->getCurrentThreadId(); }
|
||||
|
||||
}}} // apache::thrift::concurrency
|
|
@ -24,6 +24,18 @@
|
|||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_BOOST_THREAD
|
||||
#include <boost/thread.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PTHREAD_H
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
class Thread;
|
||||
|
@ -68,7 +80,16 @@ class Thread {
|
|||
|
||||
public:
|
||||
|
||||
typedef uint64_t id_t;
|
||||
#ifdef USE_BOOST_THREAD
|
||||
typedef boost::thread::id id_t;
|
||||
|
||||
static inline bool is_current(id_t t) { return t == boost::this_thread::get_id(); }
|
||||
static inline id_t get_current() { return boost::this_thread::get_id(); }
|
||||
#else
|
||||
typedef pthread_t id_t;
|
||||
static inline bool is_current(id_t t) { return pthread_equal(pthread_self(), t); }
|
||||
static inline id_t get_current() { return pthread_self(); }
|
||||
#endif
|
||||
|
||||
virtual ~Thread() {};
|
||||
|
||||
|
|
|
@ -0,0 +1,585 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "ThreadManager.h"
|
||||
#include "Exception.h"
|
||||
#include "Monitor.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <assert.h>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
#if defined(DEBUG)
|
||||
#include <iostream>
|
||||
#endif //defined(DEBUG)
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
using boost::shared_ptr;
|
||||
using boost::dynamic_pointer_cast;
|
||||
|
||||
/**
|
||||
* ThreadManager class
|
||||
*
|
||||
* This class manages a pool of threads. It uses a ThreadFactory to create
|
||||
* threads. It never actually creates or destroys worker threads, rather
|
||||
* it maintains statistics on number of idle threads, number of active threads,
|
||||
* task backlog, and average wait and service times.
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class ThreadManager::Impl : public ThreadManager {
|
||||
|
||||
public:
|
||||
Impl() :
|
||||
workerCount_(0),
|
||||
workerMaxCount_(0),
|
||||
idleCount_(0),
|
||||
pendingTaskCountMax_(0),
|
||||
expiredCount_(0),
|
||||
state_(ThreadManager::UNINITIALIZED),
|
||||
monitor_(&mutex_),
|
||||
maxMonitor_(&mutex_) {}
|
||||
|
||||
~Impl() { stop(); }
|
||||
|
||||
void start();
|
||||
|
||||
void stop() { stopImpl(false); }
|
||||
|
||||
void join() { stopImpl(true); }
|
||||
|
||||
ThreadManager::STATE state() const {
|
||||
return state_;
|
||||
}
|
||||
|
||||
shared_ptr<ThreadFactory> threadFactory() const {
|
||||
Synchronized s(monitor_);
|
||||
return threadFactory_;
|
||||
}
|
||||
|
||||
void threadFactory(shared_ptr<ThreadFactory> value) {
|
||||
Synchronized s(monitor_);
|
||||
threadFactory_ = value;
|
||||
}
|
||||
|
||||
void addWorker(size_t value);
|
||||
|
||||
void removeWorker(size_t value);
|
||||
|
||||
size_t idleWorkerCount() const {
|
||||
return idleCount_;
|
||||
}
|
||||
|
||||
size_t workerCount() const {
|
||||
Synchronized s(monitor_);
|
||||
return workerCount_;
|
||||
}
|
||||
|
||||
size_t pendingTaskCount() const {
|
||||
Synchronized s(monitor_);
|
||||
return tasks_.size();
|
||||
}
|
||||
|
||||
size_t totalTaskCount() const {
|
||||
Synchronized s(monitor_);
|
||||
return tasks_.size() + workerCount_ - idleCount_;
|
||||
}
|
||||
|
||||
size_t pendingTaskCountMax() const {
|
||||
Synchronized s(monitor_);
|
||||
return pendingTaskCountMax_;
|
||||
}
|
||||
|
||||
size_t expiredTaskCount() {
|
||||
Synchronized s(monitor_);
|
||||
size_t result = expiredCount_;
|
||||
expiredCount_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void pendingTaskCountMax(const size_t value) {
|
||||
Synchronized s(monitor_);
|
||||
pendingTaskCountMax_ = value;
|
||||
}
|
||||
|
||||
bool canSleep();
|
||||
|
||||
void add(shared_ptr<Runnable> value, int64_t timeout, int64_t expiration);
|
||||
|
||||
void remove(shared_ptr<Runnable> task);
|
||||
|
||||
shared_ptr<Runnable> removeNextPending();
|
||||
|
||||
void removeExpiredTasks();
|
||||
|
||||
void setExpireCallback(ExpireCallback expireCallback);
|
||||
|
||||
private:
|
||||
void stopImpl(bool join);
|
||||
|
||||
size_t workerCount_;
|
||||
size_t workerMaxCount_;
|
||||
size_t idleCount_;
|
||||
size_t pendingTaskCountMax_;
|
||||
size_t expiredCount_;
|
||||
ExpireCallback expireCallback_;
|
||||
|
||||
ThreadManager::STATE state_;
|
||||
shared_ptr<ThreadFactory> threadFactory_;
|
||||
|
||||
|
||||
friend class ThreadManager::Task;
|
||||
std::queue<shared_ptr<Task> > tasks_;
|
||||
Mutex mutex_;
|
||||
Monitor monitor_;
|
||||
Monitor maxMonitor_;
|
||||
Monitor workerMonitor_;
|
||||
|
||||
friend class ThreadManager::Worker;
|
||||
std::set<shared_ptr<Thread> > workers_;
|
||||
std::set<shared_ptr<Thread> > deadWorkers_;
|
||||
std::map<const Thread::id_t, shared_ptr<Thread> > idMap_;
|
||||
};
|
||||
|
||||
class ThreadManager::Task : public Runnable {
|
||||
|
||||
public:
|
||||
enum STATE {
|
||||
WAITING,
|
||||
EXECUTING,
|
||||
CANCELLED,
|
||||
COMPLETE
|
||||
};
|
||||
|
||||
Task(shared_ptr<Runnable> runnable, int64_t expiration=0LL) :
|
||||
runnable_(runnable),
|
||||
state_(WAITING),
|
||||
expireTime_(expiration != 0LL ? Util::currentTime() + expiration : 0LL) {}
|
||||
|
||||
~Task() {}
|
||||
|
||||
void run() {
|
||||
if (state_ == EXECUTING) {
|
||||
runnable_->run();
|
||||
state_ = COMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<Runnable> getRunnable() {
|
||||
return runnable_;
|
||||
}
|
||||
|
||||
int64_t getExpireTime() const {
|
||||
return expireTime_;
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<Runnable> runnable_;
|
||||
friend class ThreadManager::Worker;
|
||||
STATE state_;
|
||||
int64_t expireTime_;
|
||||
};
|
||||
|
||||
class ThreadManager::Worker: public Runnable {
|
||||
enum STATE {
|
||||
UNINITIALIZED,
|
||||
STARTING,
|
||||
STARTED,
|
||||
STOPPING,
|
||||
STOPPED
|
||||
};
|
||||
|
||||
public:
|
||||
Worker(ThreadManager::Impl* manager) :
|
||||
manager_(manager),
|
||||
state_(UNINITIALIZED),
|
||||
idle_(false) {}
|
||||
|
||||
~Worker() {}
|
||||
|
||||
private:
|
||||
bool isActive() const {
|
||||
return
|
||||
(manager_->workerCount_ <= manager_->workerMaxCount_) ||
|
||||
(manager_->state_ == JOINING && !manager_->tasks_.empty());
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Worker entry point
|
||||
*
|
||||
* As long as worker thread is running, pull tasks off the task queue and
|
||||
* execute.
|
||||
*/
|
||||
void run() {
|
||||
bool active = false;
|
||||
bool notifyManager = false;
|
||||
|
||||
/**
|
||||
* Increment worker semaphore and notify manager if worker count reached
|
||||
* desired max
|
||||
*
|
||||
* Note: We have to release the monitor and acquire the workerMonitor
|
||||
* since that is what the manager blocks on for worker add/remove
|
||||
*/
|
||||
{
|
||||
Synchronized s(manager_->monitor_);
|
||||
active = manager_->workerCount_ < manager_->workerMaxCount_;
|
||||
if (active) {
|
||||
manager_->workerCount_++;
|
||||
notifyManager = manager_->workerCount_ == manager_->workerMaxCount_;
|
||||
}
|
||||
}
|
||||
|
||||
if (notifyManager) {
|
||||
Synchronized s(manager_->workerMonitor_);
|
||||
manager_->workerMonitor_.notify();
|
||||
notifyManager = false;
|
||||
}
|
||||
|
||||
while (active) {
|
||||
shared_ptr<ThreadManager::Task> task;
|
||||
|
||||
/**
|
||||
* While holding manager monitor block for non-empty task queue (Also
|
||||
* check that the thread hasn't been requested to stop). Once the queue
|
||||
* is non-empty, dequeue a task, release monitor, and execute. If the
|
||||
* worker max count has been decremented such that we exceed it, mark
|
||||
* ourself inactive, decrement the worker count and notify the manager
|
||||
* (technically we're notifying the next blocked thread but eventually
|
||||
* the manager will see it.
|
||||
*/
|
||||
{
|
||||
Guard g(manager_->mutex_);
|
||||
active = isActive();
|
||||
|
||||
while (active && manager_->tasks_.empty()) {
|
||||
manager_->idleCount_++;
|
||||
idle_ = true;
|
||||
manager_->monitor_.wait();
|
||||
active = isActive();
|
||||
idle_ = false;
|
||||
manager_->idleCount_--;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
manager_->removeExpiredTasks();
|
||||
|
||||
if (!manager_->tasks_.empty()) {
|
||||
task = manager_->tasks_.front();
|
||||
manager_->tasks_.pop();
|
||||
if (task->state_ == ThreadManager::Task::WAITING) {
|
||||
task->state_ = ThreadManager::Task::EXECUTING;
|
||||
}
|
||||
|
||||
/* If we have a pending task max and we just dropped below it, wakeup any
|
||||
thread that might be blocked on add. */
|
||||
if (manager_->pendingTaskCountMax_ != 0 &&
|
||||
manager_->tasks_.size() <= manager_->pendingTaskCountMax_ - 1) {
|
||||
manager_->maxMonitor_.notify();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
idle_ = true;
|
||||
manager_->workerCount_--;
|
||||
notifyManager = (manager_->workerCount_ == manager_->workerMaxCount_);
|
||||
}
|
||||
}
|
||||
|
||||
if (task != NULL) {
|
||||
if (task->state_ == ThreadManager::Task::EXECUTING) {
|
||||
try {
|
||||
task->run();
|
||||
} catch(...) {
|
||||
// XXX need to log this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Synchronized s(manager_->workerMonitor_);
|
||||
manager_->deadWorkers_.insert(this->thread());
|
||||
if (notifyManager) {
|
||||
manager_->workerMonitor_.notify();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
ThreadManager::Impl* manager_;
|
||||
friend class ThreadManager::Impl;
|
||||
STATE state_;
|
||||
bool idle_;
|
||||
};
|
||||
|
||||
|
||||
void ThreadManager::Impl::addWorker(size_t value) {
|
||||
std::set<shared_ptr<Thread> > newThreads;
|
||||
for (size_t ix = 0; ix < value; ix++) {
|
||||
shared_ptr<ThreadManager::Worker> worker = shared_ptr<ThreadManager::Worker>(new ThreadManager::Worker(this));
|
||||
newThreads.insert(threadFactory_->newThread(worker));
|
||||
}
|
||||
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
workerMaxCount_ += value;
|
||||
workers_.insert(newThreads.begin(), newThreads.end());
|
||||
}
|
||||
|
||||
for (std::set<shared_ptr<Thread> >::iterator ix = newThreads.begin(); ix != newThreads.end(); ix++) {
|
||||
shared_ptr<ThreadManager::Worker> worker = dynamic_pointer_cast<ThreadManager::Worker, Runnable>((*ix)->runnable());
|
||||
worker->state_ = ThreadManager::Worker::STARTING;
|
||||
(*ix)->start();
|
||||
idMap_.insert(std::pair<const Thread::id_t, shared_ptr<Thread> >((*ix)->getId(), *ix));
|
||||
}
|
||||
|
||||
{
|
||||
Synchronized s(workerMonitor_);
|
||||
while (workerCount_ != workerMaxCount_) {
|
||||
workerMonitor_.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadManager::Impl::start() {
|
||||
|
||||
if (state_ == ThreadManager::STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
if (state_ == ThreadManager::UNINITIALIZED) {
|
||||
if (threadFactory_ == NULL) {
|
||||
throw InvalidArgumentException();
|
||||
}
|
||||
state_ = ThreadManager::STARTED;
|
||||
monitor_.notifyAll();
|
||||
}
|
||||
|
||||
while (state_ == STARTING) {
|
||||
monitor_.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadManager::Impl::stopImpl(bool join) {
|
||||
bool doStop = false;
|
||||
if (state_ == ThreadManager::STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
if (state_ != ThreadManager::STOPPING &&
|
||||
state_ != ThreadManager::JOINING &&
|
||||
state_ != ThreadManager::STOPPED) {
|
||||
doStop = true;
|
||||
state_ = join ? ThreadManager::JOINING : ThreadManager::STOPPING;
|
||||
}
|
||||
}
|
||||
|
||||
if (doStop) {
|
||||
removeWorker(workerCount_);
|
||||
}
|
||||
|
||||
// XXX
|
||||
// should be able to block here for transition to STOPPED since we're no
|
||||
// using shared_ptrs
|
||||
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
state_ = ThreadManager::STOPPED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ThreadManager::Impl::removeWorker(size_t value) {
|
||||
std::set<shared_ptr<Thread> > removedThreads;
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
if (value > workerMaxCount_) {
|
||||
throw InvalidArgumentException();
|
||||
}
|
||||
|
||||
workerMaxCount_ -= value;
|
||||
|
||||
if (idleCount_ < value) {
|
||||
for (size_t ix = 0; ix < idleCount_; ix++) {
|
||||
monitor_.notify();
|
||||
}
|
||||
} else {
|
||||
monitor_.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Synchronized s(workerMonitor_);
|
||||
|
||||
while (workerCount_ != workerMaxCount_) {
|
||||
workerMonitor_.wait();
|
||||
}
|
||||
|
||||
for (std::set<shared_ptr<Thread> >::iterator ix = deadWorkers_.begin(); ix != deadWorkers_.end(); ix++) {
|
||||
workers_.erase(*ix);
|
||||
idMap_.erase((*ix)->getId());
|
||||
}
|
||||
|
||||
deadWorkers_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool ThreadManager::Impl::canSleep() {
|
||||
const Thread::id_t id = threadFactory_->getCurrentThreadId();
|
||||
return idMap_.find(id) == idMap_.end();
|
||||
}
|
||||
|
||||
void ThreadManager::Impl::add(shared_ptr<Runnable> value,
|
||||
int64_t timeout,
|
||||
int64_t expiration) {
|
||||
Guard g(mutex_, timeout);
|
||||
|
||||
if (!g) {
|
||||
throw TimedOutException();
|
||||
}
|
||||
|
||||
if (state_ != ThreadManager::STARTED) {
|
||||
throw IllegalStateException("ThreadManager::Impl::add ThreadManager "
|
||||
"not started");
|
||||
}
|
||||
|
||||
removeExpiredTasks();
|
||||
if (pendingTaskCountMax_ > 0 && (tasks_.size() >= pendingTaskCountMax_)) {
|
||||
if (canSleep() && timeout >= 0) {
|
||||
while (pendingTaskCountMax_ > 0 && tasks_.size() >= pendingTaskCountMax_) {
|
||||
// This is thread safe because the mutex is shared between monitors.
|
||||
maxMonitor_.wait(timeout);
|
||||
}
|
||||
} else {
|
||||
throw TooManyPendingTasksException();
|
||||
}
|
||||
}
|
||||
|
||||
tasks_.push(shared_ptr<ThreadManager::Task>(new ThreadManager::Task(value, expiration)));
|
||||
|
||||
// If idle thread is available notify it, otherwise all worker threads are
|
||||
// running and will get around to this task in time.
|
||||
if (idleCount_ > 0) {
|
||||
monitor_.notify();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadManager::Impl::remove(shared_ptr<Runnable> task) {
|
||||
(void) task;
|
||||
Synchronized s(monitor_);
|
||||
if (state_ != ThreadManager::STARTED) {
|
||||
throw IllegalStateException("ThreadManager::Impl::remove ThreadManager not "
|
||||
"started");
|
||||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<Runnable> ThreadManager::Impl::removeNextPending() {
|
||||
Guard g(mutex_);
|
||||
if (state_ != ThreadManager::STARTED) {
|
||||
throw IllegalStateException("ThreadManager::Impl::removeNextPending "
|
||||
"ThreadManager not started");
|
||||
}
|
||||
|
||||
if (tasks_.empty()) {
|
||||
return boost::shared_ptr<Runnable>();
|
||||
}
|
||||
|
||||
shared_ptr<ThreadManager::Task> task = tasks_.front();
|
||||
tasks_.pop();
|
||||
|
||||
return task->getRunnable();
|
||||
}
|
||||
|
||||
void ThreadManager::Impl::removeExpiredTasks() {
|
||||
int64_t now = 0LL; // we won't ask for the time untile we need it
|
||||
|
||||
// note that this loop breaks at the first non-expiring task
|
||||
while (!tasks_.empty()) {
|
||||
shared_ptr<ThreadManager::Task> task = tasks_.front();
|
||||
if (task->getExpireTime() == 0LL) {
|
||||
break;
|
||||
}
|
||||
if (now == 0LL) {
|
||||
now = Util::currentTime();
|
||||
}
|
||||
if (task->getExpireTime() > now) {
|
||||
break;
|
||||
}
|
||||
if (expireCallback_) {
|
||||
expireCallback_(task->getRunnable());
|
||||
}
|
||||
tasks_.pop();
|
||||
expiredCount_++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ThreadManager::Impl::setExpireCallback(ExpireCallback expireCallback) {
|
||||
expireCallback_ = expireCallback;
|
||||
}
|
||||
|
||||
class SimpleThreadManager : public ThreadManager::Impl {
|
||||
|
||||
public:
|
||||
SimpleThreadManager(size_t workerCount=4, size_t pendingTaskCountMax=0) :
|
||||
workerCount_(workerCount),
|
||||
pendingTaskCountMax_(pendingTaskCountMax),
|
||||
firstTime_(true) {
|
||||
}
|
||||
|
||||
void start() {
|
||||
ThreadManager::Impl::pendingTaskCountMax(pendingTaskCountMax_);
|
||||
ThreadManager::Impl::start();
|
||||
addWorker(workerCount_);
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t workerCount_;
|
||||
const size_t pendingTaskCountMax_;
|
||||
bool firstTime_;
|
||||
Monitor monitor_;
|
||||
};
|
||||
|
||||
|
||||
shared_ptr<ThreadManager> ThreadManager::newThreadManager() {
|
||||
return shared_ptr<ThreadManager>(new ThreadManager::Impl());
|
||||
}
|
||||
|
||||
shared_ptr<ThreadManager> ThreadManager::newSimpleThreadManager(size_t count, size_t pendingTaskCountMax) {
|
||||
return shared_ptr<ThreadManager>(new SimpleThreadManager(count, pendingTaskCountMax));
|
||||
}
|
||||
|
||||
}}} // apache::thrift::concurrency
|
||||
|
|
@ -93,7 +93,7 @@ class ThreadManager {
|
|||
STOPPED
|
||||
};
|
||||
|
||||
virtual const STATE state() const = 0;
|
||||
virtual STATE state() const = 0;
|
||||
|
||||
virtual boost::shared_ptr<ThreadFactory> threadFactory() const = 0;
|
||||
|
||||
|
|
292
nativeLib/org.apache.thrift/include/concurrency/TimerManager.cpp
Normal file
292
nativeLib/org.apache.thrift/include/concurrency/TimerManager.cpp
Normal file
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "TimerManager.h"
|
||||
#include "Exception.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
using boost::shared_ptr;
|
||||
|
||||
/**
|
||||
* TimerManager class
|
||||
*
|
||||
* @version $Id:$
|
||||
*/
|
||||
class TimerManager::Task : public Runnable {
|
||||
|
||||
public:
|
||||
enum STATE {
|
||||
WAITING,
|
||||
EXECUTING,
|
||||
CANCELLED,
|
||||
COMPLETE
|
||||
};
|
||||
|
||||
Task(shared_ptr<Runnable> runnable) :
|
||||
runnable_(runnable),
|
||||
state_(WAITING) {}
|
||||
|
||||
~Task() {
|
||||
}
|
||||
|
||||
void run() {
|
||||
if (state_ == EXECUTING) {
|
||||
runnable_->run();
|
||||
state_ = COMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<Runnable> runnable_;
|
||||
friend class TimerManager::Dispatcher;
|
||||
STATE state_;
|
||||
};
|
||||
|
||||
class TimerManager::Dispatcher: public Runnable {
|
||||
|
||||
public:
|
||||
Dispatcher(TimerManager* manager) :
|
||||
manager_(manager) {}
|
||||
|
||||
~Dispatcher() {}
|
||||
|
||||
/**
|
||||
* Dispatcher entry point
|
||||
*
|
||||
* As long as dispatcher thread is running, pull tasks off the task taskMap_
|
||||
* and execute.
|
||||
*/
|
||||
void run() {
|
||||
{
|
||||
Synchronized s(manager_->monitor_);
|
||||
if (manager_->state_ == TimerManager::STARTING) {
|
||||
manager_->state_ = TimerManager::STARTED;
|
||||
manager_->monitor_.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
std::set<shared_ptr<TimerManager::Task> > expiredTasks;
|
||||
{
|
||||
Synchronized s(manager_->monitor_);
|
||||
task_iterator expiredTaskEnd;
|
||||
int64_t now = Util::currentTime();
|
||||
while (manager_->state_ == TimerManager::STARTED &&
|
||||
(expiredTaskEnd = manager_->taskMap_.upper_bound(now)) == manager_->taskMap_.begin()) {
|
||||
int64_t timeout = 0LL;
|
||||
if (!manager_->taskMap_.empty()) {
|
||||
timeout = manager_->taskMap_.begin()->first - now;
|
||||
}
|
||||
assert((timeout != 0 && manager_->taskCount_ > 0) || (timeout == 0 && manager_->taskCount_ == 0));
|
||||
try {
|
||||
manager_->monitor_.wait(timeout);
|
||||
} catch (TimedOutException &) {}
|
||||
now = Util::currentTime();
|
||||
}
|
||||
|
||||
if (manager_->state_ == TimerManager::STARTED) {
|
||||
for (task_iterator ix = manager_->taskMap_.begin(); ix != expiredTaskEnd; ix++) {
|
||||
shared_ptr<TimerManager::Task> task = ix->second;
|
||||
expiredTasks.insert(task);
|
||||
if (task->state_ == TimerManager::Task::WAITING) {
|
||||
task->state_ = TimerManager::Task::EXECUTING;
|
||||
}
|
||||
manager_->taskCount_--;
|
||||
}
|
||||
manager_->taskMap_.erase(manager_->taskMap_.begin(), expiredTaskEnd);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::set<shared_ptr<Task> >::iterator ix = expiredTasks.begin(); ix != expiredTasks.end(); ix++) {
|
||||
(*ix)->run();
|
||||
}
|
||||
|
||||
} while (manager_->state_ == TimerManager::STARTED);
|
||||
|
||||
{
|
||||
Synchronized s(manager_->monitor_);
|
||||
if (manager_->state_ == TimerManager::STOPPING) {
|
||||
manager_->state_ = TimerManager::STOPPED;
|
||||
manager_->monitor_.notify();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
TimerManager* manager_;
|
||||
friend class TimerManager;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4355) // 'this' used in base member initializer list
|
||||
#endif
|
||||
|
||||
TimerManager::TimerManager() :
|
||||
taskCount_(0),
|
||||
state_(TimerManager::UNINITIALIZED),
|
||||
dispatcher_(shared_ptr<Dispatcher>(new Dispatcher(this))) {
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
TimerManager::~TimerManager() {
|
||||
|
||||
// If we haven't been explicitly stopped, do so now. We don't need to grab
|
||||
// the monitor here, since stop already takes care of reentrancy.
|
||||
|
||||
if (state_ != STOPPED) {
|
||||
try {
|
||||
stop();
|
||||
} catch(...) {
|
||||
throw;
|
||||
// uhoh
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimerManager::start() {
|
||||
bool doStart = false;
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
if (threadFactory_ == NULL) {
|
||||
throw InvalidArgumentException();
|
||||
}
|
||||
if (state_ == TimerManager::UNINITIALIZED) {
|
||||
state_ = TimerManager::STARTING;
|
||||
doStart = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doStart) {
|
||||
dispatcherThread_ = threadFactory_->newThread(dispatcher_);
|
||||
dispatcherThread_->start();
|
||||
}
|
||||
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
while (state_ == TimerManager::STARTING) {
|
||||
monitor_.wait();
|
||||
}
|
||||
assert(state_ != TimerManager::STARTING);
|
||||
}
|
||||
}
|
||||
|
||||
void TimerManager::stop() {
|
||||
bool doStop = false;
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
if (state_ == TimerManager::UNINITIALIZED) {
|
||||
state_ = TimerManager::STOPPED;
|
||||
} else if (state_ != STOPPING && state_ != STOPPED) {
|
||||
doStop = true;
|
||||
state_ = STOPPING;
|
||||
monitor_.notifyAll();
|
||||
}
|
||||
while (state_ != STOPPED) {
|
||||
monitor_.wait();
|
||||
}
|
||||
}
|
||||
|
||||
if (doStop) {
|
||||
// Clean up any outstanding tasks
|
||||
taskMap_.clear();
|
||||
|
||||
// Remove dispatcher's reference to us.
|
||||
dispatcher_->manager_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<const ThreadFactory> TimerManager::threadFactory() const {
|
||||
Synchronized s(monitor_);
|
||||
return threadFactory_;
|
||||
}
|
||||
|
||||
void TimerManager::threadFactory(shared_ptr<const ThreadFactory> value) {
|
||||
Synchronized s(monitor_);
|
||||
threadFactory_ = value;
|
||||
}
|
||||
|
||||
size_t TimerManager::taskCount() const {
|
||||
return taskCount_;
|
||||
}
|
||||
|
||||
void TimerManager::add(shared_ptr<Runnable> task, int64_t timeout) {
|
||||
int64_t now = Util::currentTime();
|
||||
timeout += now;
|
||||
|
||||
{
|
||||
Synchronized s(monitor_);
|
||||
if (state_ != TimerManager::STARTED) {
|
||||
throw IllegalStateException();
|
||||
}
|
||||
|
||||
// If the task map is empty, we will kick the dispatcher for sure. Otherwise, we kick him
|
||||
// if the expiration time is shorter than the current value. Need to test before we insert,
|
||||
// because the new task might insert at the front.
|
||||
bool notifyRequired = (taskCount_ == 0) ? true : timeout < taskMap_.begin()->first;
|
||||
|
||||
taskCount_++;
|
||||
taskMap_.insert(std::pair<int64_t, shared_ptr<Task> >(timeout, shared_ptr<Task>(new Task(task))));
|
||||
|
||||
// If the task map was empty, or if we have an expiration that is earlier
|
||||
// than any previously seen, kick the dispatcher so it can update its
|
||||
// timeout
|
||||
if (notifyRequired) {
|
||||
monitor_.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimerManager::add(shared_ptr<Runnable> task, const struct timespec& value) {
|
||||
|
||||
int64_t expiration;
|
||||
Util::toMilliseconds(expiration, value);
|
||||
|
||||
int64_t now = Util::currentTime();
|
||||
|
||||
if (expiration < now) {
|
||||
throw InvalidArgumentException();
|
||||
}
|
||||
|
||||
add(task, expiration - now);
|
||||
}
|
||||
|
||||
|
||||
void TimerManager::remove(shared_ptr<Runnable> task) {
|
||||
(void) task;
|
||||
Synchronized s(monitor_);
|
||||
if (state_ != TimerManager::STARTED) {
|
||||
throw IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
TimerManager::STATE TimerManager::state() const { return state_; }
|
||||
|
||||
}}} // apache::thrift::concurrency
|
||||
|
|
@ -99,7 +99,7 @@ class TimerManager {
|
|||
STOPPED
|
||||
};
|
||||
|
||||
virtual const STATE state() const;
|
||||
virtual STATE state() const;
|
||||
|
||||
private:
|
||||
boost::shared_ptr<const ThreadFactory> threadFactory_;
|
||||
|
|
55
nativeLib/org.apache.thrift/include/concurrency/Util.cpp
Normal file
55
nativeLib/org.apache.thrift/include/concurrency/Util.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "Util.h"
|
||||
|
||||
#if defined(HAVE_CLOCK_GETTIME)
|
||||
#include <time.h>
|
||||
#elif defined(HAVE_SYS_TIME_H)
|
||||
#include <sys/time.h>
|
||||
#endif // defined(HAVE_CLOCK_GETTIME)
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
int64_t Util::currentTimeTicks(int64_t ticksPerSec) {
|
||||
int64_t result;
|
||||
|
||||
#if defined(HAVE_CLOCK_GETTIME)
|
||||
struct timespec now;
|
||||
int ret = clock_gettime(CLOCK_REALTIME, &now);
|
||||
assert(ret == 0);
|
||||
ret = ret; //squelching "unused variable" warning
|
||||
toTicks(result, now, ticksPerSec);
|
||||
#elif defined(HAVE_GETTIMEOFDAY)
|
||||
struct timeval now;
|
||||
int ret = gettimeofday(&now, NULL);
|
||||
assert(ret == 0);
|
||||
toTicks(result, now, ticksPerSec);
|
||||
#else
|
||||
#error "No high-precision clock is available."
|
||||
#endif // defined(HAVE_CLOCK_GETTIME)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}}} // apache::thrift::concurrency
|
|
@ -24,7 +24,10 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace apache { namespace thrift { namespace concurrency {
|
||||
|
||||
|
@ -64,11 +67,11 @@ class Util {
|
|||
}
|
||||
|
||||
static void toTimeval(struct timeval& result, int64_t value) {
|
||||
result.tv_sec = value / MS_PER_S; // ms to s
|
||||
result.tv_sec = (uint32_t)(value / MS_PER_S); // ms to s
|
||||
result.tv_usec = (value % MS_PER_S) * US_PER_MS; // ms to us
|
||||
}
|
||||
|
||||
static const void toTicks(int64_t& result, int64_t secs, int64_t oldTicks,
|
||||
static void toTicks(int64_t& result, int64_t secs, int64_t oldTicks,
|
||||
int64_t oldTicksPerSec, int64_t newTicksPerSec) {
|
||||
result = secs * newTicksPerSec;
|
||||
result += oldTicks * newTicksPerSec / oldTicksPerSec;
|
||||
|
@ -81,7 +84,7 @@ class Util {
|
|||
/**
|
||||
* Converts struct timespec to arbitrary-sized ticks since epoch
|
||||
*/
|
||||
static const void toTicks(int64_t& result,
|
||||
static void toTicks(int64_t& result,
|
||||
const struct timespec& value,
|
||||
int64_t ticksPerSec) {
|
||||
return toTicks(result, value.tv_sec, value.tv_nsec, NS_PER_S, ticksPerSec);
|
||||
|
@ -90,7 +93,7 @@ class Util {
|
|||
/**
|
||||
* Converts struct timeval to arbitrary-sized ticks since epoch
|
||||
*/
|
||||
static const void toTicks(int64_t& result,
|
||||
static void toTicks(int64_t& result,
|
||||
const struct timeval& value,
|
||||
int64_t ticksPerSec) {
|
||||
return toTicks(result, value.tv_sec, value.tv_usec, US_PER_S, ticksPerSec);
|
||||
|
@ -99,7 +102,7 @@ class Util {
|
|||
/**
|
||||
* Converts struct timespec to milliseconds
|
||||
*/
|
||||
static const void toMilliseconds(int64_t& result,
|
||||
static void toMilliseconds(int64_t& result,
|
||||
const struct timespec& value) {
|
||||
return toTicks(result, value, MS_PER_S);
|
||||
}
|
||||
|
@ -107,7 +110,7 @@ class Util {
|
|||
/**
|
||||
* Converts struct timeval to milliseconds
|
||||
*/
|
||||
static const void toMilliseconds(int64_t& result,
|
||||
static void toMilliseconds(int64_t& result,
|
||||
const struct timeval& value) {
|
||||
return toTicks(result, value, MS_PER_S);
|
||||
}
|
||||
|
@ -115,31 +118,31 @@ class Util {
|
|||
/**
|
||||
* Converts struct timespec to microseconds
|
||||
*/
|
||||
static const void toUsec(int64_t& result, const struct timespec& value) {
|
||||
static void toUsec(int64_t& result, const struct timespec& value) {
|
||||
return toTicks(result, value, US_PER_S);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts struct timeval to microseconds
|
||||
*/
|
||||
static const void toUsec(int64_t& result, const struct timeval& value) {
|
||||
static void toUsec(int64_t& result, const struct timeval& value) {
|
||||
return toTicks(result, value, US_PER_S);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current time as a number of arbitrary-size ticks from epoch
|
||||
*/
|
||||
static const int64_t currentTimeTicks(int64_t ticksPerSec);
|
||||
static int64_t currentTimeTicks(int64_t ticksPerSec);
|
||||
|
||||
/**
|
||||
* Get current time as milliseconds from epoch
|
||||
*/
|
||||
static const int64_t currentTime() { return currentTimeTicks(MS_PER_S); }
|
||||
static int64_t currentTime() { return currentTimeTicks(MS_PER_S); }
|
||||
|
||||
/**
|
||||
* Get current time as micros from epoch
|
||||
*/
|
||||
static const int64_t currentTimeUsec() { return currentTimeTicks(US_PER_S); }
|
||||
static int64_t currentTimeUsec() { return currentTimeTicks(US_PER_S); }
|
||||
};
|
||||
|
||||
}}} // apache::thrift::concurrency
|
||||
|
|
|
@ -1,360 +0,0 @@
|
|||
/* config.h. Generated from config.hin by configure. */
|
||||
/* config.hin. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if the AI_ADDRCONFIG symbol is unavailable */
|
||||
/* #undef AI_ADDRCONFIG */
|
||||
|
||||
/* Possible value for SIGNED_RIGHT_SHIFT_IS */
|
||||
#define ARITHMETIC_RIGHT_SHIFT 1
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
/* #undef CRAY_STACKSEG_END */
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
/* #undef C_ALLOCA */
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#define HAVE_ALLOCA 1
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#define HAVE_ALLOCA_H 1
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#define HAVE_ARPA_INET_H 1
|
||||
|
||||
/* define if the Boost library is available */
|
||||
#define HAVE_BOOST /**/
|
||||
|
||||
/* Define to 1 if you have the `bzero' function. */
|
||||
#define HAVE_BZERO 1
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#define HAVE_CLOCK_GETTIME 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_STRERROR_R 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
/* #undef HAVE_DOPRNT */
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `ftruncate' function. */
|
||||
#define HAVE_FTRUNCATE 1
|
||||
|
||||
/* Define to 1 if you have the `gethostbyname' function. */
|
||||
#define HAVE_GETHOSTBYNAME 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* define if libevent is available */
|
||||
/* #undef HAVE_LIBEVENT */
|
||||
|
||||
/* Define to 1 if you have the <libintl.h> header file. */
|
||||
#define HAVE_LIBINTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#define HAVE_LIBPTHREAD 1
|
||||
|
||||
/* Define to 1 if you have the `rt' library (-lrt). */
|
||||
#define HAVE_LIBRT 1
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
/* #undef HAVE_LIBSOCKET */
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#define HAVE_MALLOC 1
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#define HAVE_MALLOC_H 1
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#define HAVE_MEMMOVE 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define HAVE_MEMSET 1
|
||||
|
||||
/* Define to 1 if you have the `mkdir' function. */
|
||||
#define HAVE_MKDIR 1
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#define HAVE_NETDB_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#define HAVE_NETINET_IN_H 1
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file. */
|
||||
#define HAVE_PTHREAD_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `ptrdiff_t'. */
|
||||
#define HAVE_PTRDIFF_T 1
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#define HAVE_REALLOC 1
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#define HAVE_REALPATH 1
|
||||
|
||||
/* Define to 1 if you have the `sched_get_priority_max' function. */
|
||||
#define HAVE_SCHED_GET_PRIORITY_MAX 1
|
||||
|
||||
/* Define to 1 if you have the `sched_get_priority_min' function. */
|
||||
#define HAVE_SCHED_GET_PRIORITY_MIN 1
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#define HAVE_SELECT 1
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#define HAVE_SOCKET 1
|
||||
|
||||
/* Define to 1 if you have the `sqrt' function. */
|
||||
#define HAVE_SQRT 1
|
||||
|
||||
/* Define to 1 if `stat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#define HAVE_STDBOOL_H 1
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#define HAVE_STDDEF_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#define HAVE_STRCHR 1
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the `strerror_r' function. */
|
||||
#define HAVE_STRERROR_R 1
|
||||
|
||||
/* Define to 1 if you have the `strftime' function. */
|
||||
#define HAVE_STRFTIME 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strstr' function. */
|
||||
#define HAVE_STRSTR 1
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#define HAVE_STRTOL 1
|
||||
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#define HAVE_STRTOUL 1
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#define HAVE_SYS_SELECT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#define HAVE_SYS_SOCKET_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `vprintf' function. */
|
||||
#define HAVE_VPRINTF 1
|
||||
|
||||
/* define if zlib is available */
|
||||
#define HAVE_ZLIB /**/
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
/* #undef HAVE__BOOL */
|
||||
|
||||
/* Possible value for SIGNED_RIGHT_SHIFT_IS */
|
||||
#define LOGICAL_RIGHT_SHIFT 2
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "thrift"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "thrift"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "thrift 0.5.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "thrift"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "0.5.0"
|
||||
|
||||
/* Define to the type of arg 1 for `select'. */
|
||||
#define SELECT_TYPE_ARG1 int
|
||||
|
||||
/* Define to the type of args 2, 3 and 4 for `select'. */
|
||||
#define SELECT_TYPE_ARG234 (fd_set *)
|
||||
|
||||
/* Define to the type of arg 5 for `select'. */
|
||||
#define SELECT_TYPE_ARG5 (struct timeval *)
|
||||
|
||||
/* Indicates the effect of the right shift operator on negative signed
|
||||
integers */
|
||||
#define SIGNED_RIGHT_SHIFT_IS 1
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
/* #undef STACK_DIRECTION */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define to 1 if strerror_r returns char *. */
|
||||
#define STRERROR_R_CHAR_P 1
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
/* #undef TM_IN_SYS_TIME */
|
||||
|
||||
/* Possible value for SIGNED_RIGHT_SHIFT_IS */
|
||||
#define UNKNOWN_RIGHT_SHIFT 3
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.5.0"
|
||||
|
||||
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
||||
`char[]'. */
|
||||
/* #undef YYTEXT_POINTER */
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
/* #undef _UINT32_T */
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
/* #undef _UINT64_T */
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
/* #undef _UINT8_T */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 16 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef int16_t */
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef int32_t */
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef int64_t */
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 8 bits if such
|
||||
a type exists and the standard includes do not define it. */
|
||||
/* #undef int8_t */
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
/* #undef malloc */
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
/* #undef mode_t */
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
/* #undef off_t */
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
/* #undef realloc */
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
/* #undef ssize_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 16 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef uint16_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef uint32_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef uint64_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 8 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef uint8_t */
|
||||
|
||||
/* Define to empty if the keyword `volatile' does not work. Warning: valid
|
||||
code using `volatile' can become incorrect without. Disable with care. */
|
||||
/* #undef volatile */
|
127
nativeLib/org.apache.thrift/include/processor/PeekProcessor.cpp
Normal file
127
nativeLib/org.apache.thrift/include/processor/PeekProcessor.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "PeekProcessor.h"
|
||||
|
||||
using namespace apache::thrift::transport;
|
||||
using namespace apache::thrift::protocol;
|
||||
using namespace apache::thrift;
|
||||
|
||||
namespace apache { namespace thrift { namespace processor {
|
||||
|
||||
PeekProcessor::PeekProcessor() {
|
||||
memoryBuffer_.reset(new TMemoryBuffer());
|
||||
targetTransport_ = memoryBuffer_;
|
||||
}
|
||||
PeekProcessor::~PeekProcessor() {}
|
||||
|
||||
void PeekProcessor::initialize(boost::shared_ptr<TProcessor> actualProcessor,
|
||||
boost::shared_ptr<TProtocolFactory> protocolFactory,
|
||||
boost::shared_ptr<TPipedTransportFactory> transportFactory) {
|
||||
actualProcessor_ = actualProcessor;
|
||||
pipedProtocol_ = protocolFactory->getProtocol(targetTransport_);
|
||||
transportFactory_ = transportFactory;
|
||||
transportFactory_->initializeTargetTransport(targetTransport_);
|
||||
}
|
||||
|
||||
boost::shared_ptr<TTransport> PeekProcessor::getPipedTransport(boost::shared_ptr<TTransport> in) {
|
||||
return transportFactory_->getTransport(in);
|
||||
}
|
||||
|
||||
void PeekProcessor::setTargetTransport(boost::shared_ptr<TTransport> targetTransport) {
|
||||
targetTransport_ = targetTransport;
|
||||
if (boost::dynamic_pointer_cast<TMemoryBuffer>(targetTransport_)) {
|
||||
memoryBuffer_ = boost::dynamic_pointer_cast<TMemoryBuffer>(targetTransport);
|
||||
} else if (boost::dynamic_pointer_cast<TPipedTransport>(targetTransport_)) {
|
||||
memoryBuffer_ = boost::dynamic_pointer_cast<TMemoryBuffer>(boost::dynamic_pointer_cast<TPipedTransport>(targetTransport_)->getTargetTransport());
|
||||
}
|
||||
|
||||
if (!memoryBuffer_) {
|
||||
throw TException("Target transport must be a TMemoryBuffer or a TPipedTransport with TMemoryBuffer");
|
||||
}
|
||||
}
|
||||
|
||||
bool PeekProcessor::process(boost::shared_ptr<TProtocol> in,
|
||||
boost::shared_ptr<TProtocol> out,
|
||||
void* connectionContext) {
|
||||
|
||||
std::string fname;
|
||||
TMessageType mtype;
|
||||
int32_t seqid;
|
||||
in->readMessageBegin(fname, mtype, seqid);
|
||||
|
||||
if (mtype != T_CALL) {
|
||||
throw TException("Unexpected message type");
|
||||
}
|
||||
|
||||
// Peek at the name
|
||||
peekName(fname);
|
||||
|
||||
TType ftype;
|
||||
int16_t fid;
|
||||
while (true) {
|
||||
in->readFieldBegin(fname, ftype, fid);
|
||||
if (ftype == T_STOP) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Peek at the variable
|
||||
peek(in, ftype, fid);
|
||||
in->readFieldEnd();
|
||||
}
|
||||
in->readMessageEnd();
|
||||
in->getTransport()->readEnd();
|
||||
|
||||
//
|
||||
// All the data is now in memoryBuffer_ and ready to be processed
|
||||
//
|
||||
|
||||
// Let's first take a peek at the full data in memory
|
||||
uint8_t* buffer;
|
||||
uint32_t size;
|
||||
memoryBuffer_->getBuffer(&buffer, &size);
|
||||
peekBuffer(buffer, size);
|
||||
|
||||
// Done peeking at variables
|
||||
peekEnd();
|
||||
|
||||
bool ret = actualProcessor_->process(pipedProtocol_, out, connectionContext);
|
||||
memoryBuffer_->resetBuffer();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PeekProcessor::peekName(const std::string& fname) {
|
||||
(void) fname;
|
||||
}
|
||||
|
||||
void PeekProcessor::peekBuffer(uint8_t* buffer, uint32_t size) {
|
||||
(void) buffer;
|
||||
(void) size;
|
||||
}
|
||||
|
||||
void PeekProcessor::peek(boost::shared_ptr<TProtocol> in,
|
||||
TType ftype,
|
||||
int16_t fid) {
|
||||
(void) fid;
|
||||
in->skip(ftype);
|
||||
}
|
||||
|
||||
void PeekProcessor::peekEnd() {}
|
||||
|
||||
}}}
|
|
@ -21,10 +21,10 @@
|
|||
#define PEEKPROCESSOR_H
|
||||
|
||||
#include <string>
|
||||
#include <TProcessor.h>
|
||||
#include <transport/TTransport.h>
|
||||
#include <transport/TTransportUtils.h>
|
||||
#include <transport/TBufferTransports.h>
|
||||
#include <thrift/TProcessor.h>
|
||||
#include <thrift/transport/TTransport.h>
|
||||
#include <thrift/transport/TTransportUtils.h>
|
||||
#include <thrift/transport/TBufferTransports.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace apache { namespace thrift { namespace processor {
|
||||
|
@ -53,7 +53,8 @@ class PeekProcessor : public apache::thrift::TProcessor {
|
|||
void setTargetTransport(boost::shared_ptr<apache::thrift::transport::TTransport> targetTransport);
|
||||
|
||||
virtual bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> in,
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocol> out);
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocol> out,
|
||||
void* connectionContext);
|
||||
|
||||
// The following three functions can be overloaded by child classes to
|
||||
// achieve desired peeking behavior
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#define STATSPROCESSOR_H
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <transport/TTransport.h>
|
||||
#include <protocol/TProtocol.h>
|
||||
#include <thrift/transport/TTransport.h>
|
||||
#include <thrift/protocol/TProtocol.h>
|
||||
#include <TProcessor.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace processor {
|
||||
|
@ -39,7 +39,9 @@ public:
|
|||
{}
|
||||
virtual ~StatsProcessor() {};
|
||||
|
||||
virtual bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot, boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot) {
|
||||
virtual bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot,
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot,
|
||||
void* serverContext) {
|
||||
|
||||
piprot_ = piprot;
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "TBase64Utils.h"
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
|
||||
|
||||
static const uint8_t *kBase64EncodeTable = (const uint8_t *)
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
void base64_encode(const uint8_t *in, uint32_t len, uint8_t *buf) {
|
||||
buf[0] = kBase64EncodeTable[(in[0] >> 2) & 0x3f];
|
||||
if (len == 3) {
|
||||
buf[1] = kBase64EncodeTable[((in[0] << 4) & 0x30) | ((in[1] >> 4) & 0x0f)];
|
||||
buf[2] = kBase64EncodeTable[((in[1] << 2) & 0x3c) | ((in[2] >> 6) & 0x03)];
|
||||
buf[3] = kBase64EncodeTable[in[2] & 0x3f];
|
||||
} else if (len == 2) {
|
||||
buf[1] = kBase64EncodeTable[((in[0] << 4) & 0x30) | ((in[1] >> 4) & 0x0f)];
|
||||
buf[2] = kBase64EncodeTable[(in[1] << 2) & 0x3c];
|
||||
} else { // len == 1
|
||||
buf[1] = kBase64EncodeTable[(in[0] << 4) & 0x30];
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t kBase64DecodeTable[256] ={
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3e,0xff,0xff,0xff,0x3f,
|
||||
0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
|
||||
0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
|
||||
0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
};
|
||||
|
||||
void base64_decode(uint8_t *buf, uint32_t len) {
|
||||
buf[0] = (kBase64DecodeTable[buf[0]] << 2) |
|
||||
(kBase64DecodeTable[buf[1]] >> 4);
|
||||
if (len > 2) {
|
||||
buf[1] = ((kBase64DecodeTable[buf[1]] << 4) & 0xf0) |
|
||||
(kBase64DecodeTable[buf[2]] >> 2);
|
||||
if (len > 3) {
|
||||
buf[2] = ((kBase64DecodeTable[buf[2]] << 6) & 0xc0) |
|
||||
(kBase64DecodeTable[buf[3]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}} // apache::thrift::protocol
|
|
@ -21,6 +21,7 @@
|
|||
#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_ 1
|
||||
|
||||
#include "TProtocol.h"
|
||||
#include "TVirtualProtocol.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
@ -31,15 +32,18 @@ namespace apache { namespace thrift { namespace protocol {
|
|||
* binary format, essentially just spitting out the raw bytes.
|
||||
*
|
||||
*/
|
||||
class TBinaryProtocol : public TProtocol {
|
||||
template <class Transport_>
|
||||
class TBinaryProtocolT
|
||||
: public TVirtualProtocol< TBinaryProtocolT<Transport_> > {
|
||||
protected:
|
||||
static const int32_t VERSION_MASK = 0xffff0000;
|
||||
static const int32_t VERSION_1 = 0x80010000;
|
||||
static const int32_t VERSION_MASK = ((int32_t)0xffff0000);
|
||||
static const int32_t VERSION_1 = ((int32_t)0x80010000);
|
||||
// VERSION_2 (0x80020000) is taken by TDenseProtocol.
|
||||
|
||||
public:
|
||||
TBinaryProtocol(boost::shared_ptr<TTransport> trans) :
|
||||
TProtocol(trans),
|
||||
TBinaryProtocolT(boost::shared_ptr<Transport_> trans) :
|
||||
TVirtualProtocol< TBinaryProtocolT<Transport_> >(trans),
|
||||
trans_(trans.get()),
|
||||
string_limit_(0),
|
||||
container_limit_(0),
|
||||
strict_read_(false),
|
||||
|
@ -47,12 +51,13 @@ class TBinaryProtocol : public TProtocol {
|
|||
string_buf_(NULL),
|
||||
string_buf_size_(0) {}
|
||||
|
||||
TBinaryProtocol(boost::shared_ptr<TTransport> trans,
|
||||
TBinaryProtocolT(boost::shared_ptr<Transport_> trans,
|
||||
int32_t string_limit,
|
||||
int32_t container_limit,
|
||||
bool strict_read,
|
||||
bool strict_write) :
|
||||
TProtocol(trans),
|
||||
TVirtualProtocol< TBinaryProtocolT<Transport_> >(trans),
|
||||
trans_(trans.get()),
|
||||
string_limit_(string_limit),
|
||||
container_limit_(container_limit),
|
||||
strict_read_(strict_read),
|
||||
|
@ -60,7 +65,7 @@ class TBinaryProtocol : public TProtocol {
|
|||
string_buf_(NULL),
|
||||
string_buf_size_(0) {}
|
||||
|
||||
~TBinaryProtocol() {
|
||||
~TBinaryProtocolT() {
|
||||
if (string_buf_ != NULL) {
|
||||
std::free(string_buf_);
|
||||
string_buf_size_ = 0;
|
||||
|
@ -84,112 +89,115 @@ class TBinaryProtocol : public TProtocol {
|
|||
* Writing functions.
|
||||
*/
|
||||
|
||||
virtual uint32_t writeMessageBegin(const std::string& name,
|
||||
/*ol*/ uint32_t writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid);
|
||||
|
||||
virtual uint32_t writeMessageEnd();
|
||||
/*ol*/ uint32_t writeMessageEnd();
|
||||
|
||||
|
||||
uint32_t writeStructBegin(const char* name);
|
||||
inline uint32_t writeStructBegin(const char* name);
|
||||
|
||||
uint32_t writeStructEnd();
|
||||
inline uint32_t writeStructEnd();
|
||||
|
||||
uint32_t writeFieldBegin(const char* name,
|
||||
inline uint32_t writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId);
|
||||
|
||||
uint32_t writeFieldEnd();
|
||||
inline uint32_t writeFieldEnd();
|
||||
|
||||
uint32_t writeFieldStop();
|
||||
inline uint32_t writeFieldStop();
|
||||
|
||||
uint32_t writeMapBegin(const TType keyType,
|
||||
inline uint32_t writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size);
|
||||
|
||||
uint32_t writeMapEnd();
|
||||
inline uint32_t writeMapEnd();
|
||||
|
||||
uint32_t writeListBegin(const TType elemType,
|
||||
const uint32_t size);
|
||||
inline uint32_t writeListBegin(const TType elemType, const uint32_t size);
|
||||
|
||||
uint32_t writeListEnd();
|
||||
inline uint32_t writeListEnd();
|
||||
|
||||
uint32_t writeSetBegin(const TType elemType,
|
||||
const uint32_t size);
|
||||
inline uint32_t writeSetBegin(const TType elemType, const uint32_t size);
|
||||
|
||||
uint32_t writeSetEnd();
|
||||
inline uint32_t writeSetEnd();
|
||||
|
||||
uint32_t writeBool(const bool value);
|
||||
inline uint32_t writeBool(const bool value);
|
||||
|
||||
uint32_t writeByte(const int8_t byte);
|
||||
inline uint32_t writeByte(const int8_t byte);
|
||||
|
||||
uint32_t writeI16(const int16_t i16);
|
||||
inline uint32_t writeI16(const int16_t i16);
|
||||
|
||||
uint32_t writeI32(const int32_t i32);
|
||||
inline uint32_t writeI32(const int32_t i32);
|
||||
|
||||
uint32_t writeI64(const int64_t i64);
|
||||
inline uint32_t writeI64(const int64_t i64);
|
||||
|
||||
uint32_t writeDouble(const double dub);
|
||||
inline uint32_t writeDouble(const double dub);
|
||||
|
||||
uint32_t writeString(const std::string& str);
|
||||
template <typename StrType>
|
||||
inline uint32_t writeString(const StrType& str);
|
||||
|
||||
uint32_t writeBinary(const std::string& str);
|
||||
inline uint32_t writeBinary(const std::string& str);
|
||||
|
||||
/**
|
||||
* Reading functions
|
||||
*/
|
||||
|
||||
|
||||
uint32_t readMessageBegin(std::string& name,
|
||||
/*ol*/ uint32_t readMessageBegin(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid);
|
||||
|
||||
uint32_t readMessageEnd();
|
||||
/*ol*/ uint32_t readMessageEnd();
|
||||
|
||||
uint32_t readStructBegin(std::string& name);
|
||||
inline uint32_t readStructBegin(std::string& name);
|
||||
|
||||
uint32_t readStructEnd();
|
||||
inline uint32_t readStructEnd();
|
||||
|
||||
uint32_t readFieldBegin(std::string& name,
|
||||
inline uint32_t readFieldBegin(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId);
|
||||
|
||||
uint32_t readFieldEnd();
|
||||
inline uint32_t readFieldEnd();
|
||||
|
||||
uint32_t readMapBegin(TType& keyType,
|
||||
inline uint32_t readMapBegin(TType& keyType,
|
||||
TType& valType,
|
||||
uint32_t& size);
|
||||
|
||||
uint32_t readMapEnd();
|
||||
inline uint32_t readMapEnd();
|
||||
|
||||
uint32_t readListBegin(TType& elemType,
|
||||
uint32_t& size);
|
||||
inline uint32_t readListBegin(TType& elemType, uint32_t& size);
|
||||
|
||||
uint32_t readListEnd();
|
||||
inline uint32_t readListEnd();
|
||||
|
||||
uint32_t readSetBegin(TType& elemType,
|
||||
uint32_t& size);
|
||||
inline uint32_t readSetBegin(TType& elemType, uint32_t& size);
|
||||
|
||||
uint32_t readSetEnd();
|
||||
inline uint32_t readSetEnd();
|
||||
|
||||
uint32_t readBool(bool& value);
|
||||
inline uint32_t readBool(bool& value);
|
||||
// Provide the default readBool() implementation for std::vector<bool>
|
||||
using TVirtualProtocol< TBinaryProtocolT<Transport_> >::readBool;
|
||||
|
||||
uint32_t readByte(int8_t& byte);
|
||||
inline uint32_t readByte(int8_t& byte);
|
||||
|
||||
uint32_t readI16(int16_t& i16);
|
||||
inline uint32_t readI16(int16_t& i16);
|
||||
|
||||
uint32_t readI32(int32_t& i32);
|
||||
inline uint32_t readI32(int32_t& i32);
|
||||
|
||||
uint32_t readI64(int64_t& i64);
|
||||
inline uint32_t readI64(int64_t& i64);
|
||||
|
||||
uint32_t readDouble(double& dub);
|
||||
inline uint32_t readDouble(double& dub);
|
||||
|
||||
uint32_t readString(std::string& str);
|
||||
template<typename StrType>
|
||||
inline uint32_t readString(StrType& str);
|
||||
|
||||
uint32_t readBinary(std::string& str);
|
||||
inline uint32_t readBinary(std::string& str);
|
||||
|
||||
protected:
|
||||
uint32_t readStringBody(std::string& str, int32_t sz);
|
||||
template<typename StrType>
|
||||
uint32_t readStringBody(StrType& str, int32_t sz);
|
||||
|
||||
Transport_* trans_;
|
||||
|
||||
int32_t string_limit_;
|
||||
int32_t container_limit_;
|
||||
|
@ -205,24 +213,28 @@ class TBinaryProtocol : public TProtocol {
|
|||
|
||||
};
|
||||
|
||||
typedef TBinaryProtocolT<TTransport> TBinaryProtocol;
|
||||
|
||||
/**
|
||||
* Constructs binary protocol handlers
|
||||
*/
|
||||
class TBinaryProtocolFactory : public TProtocolFactory {
|
||||
template <class Transport_>
|
||||
class TBinaryProtocolFactoryT : public TProtocolFactory {
|
||||
public:
|
||||
TBinaryProtocolFactory() :
|
||||
TBinaryProtocolFactoryT() :
|
||||
string_limit_(0),
|
||||
container_limit_(0),
|
||||
strict_read_(false),
|
||||
strict_write_(true) {}
|
||||
|
||||
TBinaryProtocolFactory(int32_t string_limit, int32_t container_limit, bool strict_read, bool strict_write) :
|
||||
TBinaryProtocolFactoryT(int32_t string_limit, int32_t container_limit,
|
||||
bool strict_read, bool strict_write) :
|
||||
string_limit_(string_limit),
|
||||
container_limit_(container_limit),
|
||||
strict_read_(strict_read),
|
||||
strict_write_(strict_write) {}
|
||||
|
||||
virtual ~TBinaryProtocolFactory() {}
|
||||
virtual ~TBinaryProtocolFactoryT() {}
|
||||
|
||||
void setStringSizeLimit(int32_t string_limit) {
|
||||
string_limit_ = string_limit;
|
||||
|
@ -238,7 +250,19 @@ class TBinaryProtocolFactory : public TProtocolFactory {
|
|||
}
|
||||
|
||||
boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
|
||||
return boost::shared_ptr<TProtocol>(new TBinaryProtocol(trans, string_limit_, container_limit_, strict_read_, strict_write_));
|
||||
boost::shared_ptr<Transport_> specific_trans =
|
||||
boost::dynamic_pointer_cast<Transport_>(trans);
|
||||
TProtocol* prot;
|
||||
if (specific_trans) {
|
||||
prot = new TBinaryProtocolT<Transport_>(specific_trans, string_limit_,
|
||||
container_limit_, strict_read_,
|
||||
strict_write_);
|
||||
} else {
|
||||
prot = new TBinaryProtocol(trans, string_limit_, container_limit_,
|
||||
strict_read_, strict_write_);
|
||||
}
|
||||
|
||||
return boost::shared_ptr<TProtocol>(prot);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -249,6 +273,10 @@ class TBinaryProtocolFactory : public TProtocolFactory {
|
|||
|
||||
};
|
||||
|
||||
typedef TBinaryProtocolFactoryT<TTransport> TBinaryProtocolFactory;
|
||||
|
||||
}}} // apache::thrift::protocol
|
||||
|
||||
#include "TBinaryProtocol.tcc"
|
||||
|
||||
#endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_
|
||||
|
|
465
nativeLib/org.apache.thrift/include/protocol/TBinaryProtocol.tcc
Normal file
465
nativeLib/org.apache.thrift/include/protocol/TBinaryProtocol.tcc
Normal file
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
|
||||
#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1
|
||||
|
||||
#include "TBinaryProtocol.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) {
|
||||
if (this->strict_write_) {
|
||||
int32_t version = (VERSION_1) | ((int32_t)messageType);
|
||||
uint32_t wsize = 0;
|
||||
wsize += writeI32(version);
|
||||
wsize += writeString(name);
|
||||
wsize += writeI32(seqid);
|
||||
return wsize;
|
||||
} else {
|
||||
uint32_t wsize = 0;
|
||||
wsize += writeString(name);
|
||||
wsize += writeByte((int8_t)messageType);
|
||||
wsize += writeI32(seqid);
|
||||
return wsize;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeMessageEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeStructBegin(const char* name) {
|
||||
(void) name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeStructEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) {
|
||||
(void) name;
|
||||
uint32_t wsize = 0;
|
||||
wsize += writeByte((int8_t)fieldType);
|
||||
wsize += writeI16(fieldId);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeFieldEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeFieldStop() {
|
||||
return
|
||||
writeByte((int8_t)T_STOP);
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) {
|
||||
uint32_t wsize = 0;
|
||||
wsize += writeByte((int8_t)keyType);
|
||||
wsize += writeByte((int8_t)valType);
|
||||
wsize += writeI32((int32_t)size);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeMapEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeListBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
uint32_t wsize = 0;
|
||||
wsize += writeByte((int8_t) elemType);
|
||||
wsize += writeI32((int32_t)size);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeListEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeSetBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
uint32_t wsize = 0;
|
||||
wsize += writeByte((int8_t)elemType);
|
||||
wsize += writeI32((int32_t)size);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeSetEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeBool(const bool value) {
|
||||
uint8_t tmp = value ? 1 : 0;
|
||||
this->trans_->write(&tmp, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeByte(const int8_t byte) {
|
||||
this->trans_->write((uint8_t*)&byte, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeI16(const int16_t i16) {
|
||||
int16_t net = (int16_t)htons(i16);
|
||||
this->trans_->write((uint8_t*)&net, 2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeI32(const int32_t i32) {
|
||||
int32_t net = (int32_t)htonl(i32);
|
||||
this->trans_->write((uint8_t*)&net, 4);
|
||||
return 4;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeI64(const int64_t i64) {
|
||||
int64_t net = (int64_t)htonll(i64);
|
||||
this->trans_->write((uint8_t*)&net, 8);
|
||||
return 8;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeDouble(const double dub) {
|
||||
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
|
||||
|
||||
uint64_t bits = bitwise_cast<uint64_t>(dub);
|
||||
bits = htonll(bits);
|
||||
this->trans_->write((uint8_t*)&bits, 8);
|
||||
return 8;
|
||||
}
|
||||
|
||||
|
||||
template <class Transport_>
|
||||
template<typename StrType>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeString(const StrType& str) {
|
||||
if(str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
uint32_t size = static_cast<uint32_t>(str.size());
|
||||
uint32_t result = writeI32((int32_t)size);
|
||||
if (size > 0) {
|
||||
this->trans_->write((uint8_t*)str.data(), size);
|
||||
}
|
||||
return result + size;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::writeBinary(const std::string& str) {
|
||||
return TBinaryProtocolT<Transport_>::writeString(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading functions
|
||||
*/
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readMessageBegin(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) {
|
||||
uint32_t result = 0;
|
||||
int32_t sz;
|
||||
result += readI32(sz);
|
||||
|
||||
if (sz < 0) {
|
||||
// Check for correct version number
|
||||
int32_t version = sz & VERSION_MASK;
|
||||
if (version != VERSION_1) {
|
||||
throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
|
||||
}
|
||||
messageType = (TMessageType)(sz & 0x000000ff);
|
||||
result += readString(name);
|
||||
result += readI32(seqid);
|
||||
} else {
|
||||
if (this->strict_read_) {
|
||||
throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
|
||||
} else {
|
||||
// Handle pre-versioned input
|
||||
int8_t type;
|
||||
result += readStringBody(name, sz);
|
||||
result += readByte(type);
|
||||
messageType = (TMessageType)type;
|
||||
result += readI32(seqid);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readMessageEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readStructBegin(std::string& name) {
|
||||
name = "";
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readStructEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readFieldBegin(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) {
|
||||
(void) name;
|
||||
uint32_t result = 0;
|
||||
int8_t type;
|
||||
result += readByte(type);
|
||||
fieldType = (TType)type;
|
||||
if (fieldType == T_STOP) {
|
||||
fieldId = 0;
|
||||
return result;
|
||||
}
|
||||
result += readI16(fieldId);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readFieldEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readMapBegin(TType& keyType,
|
||||
TType& valType,
|
||||
uint32_t& size) {
|
||||
int8_t k, v;
|
||||
uint32_t result = 0;
|
||||
int32_t sizei;
|
||||
result += readByte(k);
|
||||
keyType = (TType)k;
|
||||
result += readByte(v);
|
||||
valType = (TType)v;
|
||||
result += readI32(sizei);
|
||||
if (sizei < 0) {
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
} else if (this->container_limit_ && sizei > this->container_limit_) {
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
size = (uint32_t)sizei;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readMapEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readListBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
int8_t e;
|
||||
uint32_t result = 0;
|
||||
int32_t sizei;
|
||||
result += readByte(e);
|
||||
elemType = (TType)e;
|
||||
result += readI32(sizei);
|
||||
if (sizei < 0) {
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
} else if (this->container_limit_ && sizei > this->container_limit_) {
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
size = (uint32_t)sizei;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readListEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readSetBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
int8_t e;
|
||||
uint32_t result = 0;
|
||||
int32_t sizei;
|
||||
result += readByte(e);
|
||||
elemType = (TType)e;
|
||||
result += readI32(sizei);
|
||||
if (sizei < 0) {
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
} else if (this->container_limit_ && sizei > this->container_limit_) {
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
size = (uint32_t)sizei;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readSetEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readBool(bool& value) {
|
||||
uint8_t b[1];
|
||||
this->trans_->readAll(b, 1);
|
||||
value = *(int8_t*)b != 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readByte(int8_t& byte) {
|
||||
uint8_t b[1];
|
||||
this->trans_->readAll(b, 1);
|
||||
byte = *(int8_t*)b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readI16(int16_t& i16) {
|
||||
union bytes {
|
||||
uint8_t b[2];
|
||||
int16_t all;
|
||||
} theBytes;
|
||||
this->trans_->readAll(theBytes.b, 2);
|
||||
i16 = (int16_t)ntohs(theBytes.all);
|
||||
return 2;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readI32(int32_t& i32) {
|
||||
union bytes {
|
||||
uint8_t b[4];
|
||||
int32_t all;
|
||||
} theBytes;
|
||||
this->trans_->readAll(theBytes.b, 4);
|
||||
i32 = (int32_t)ntohl(theBytes.all);
|
||||
return 4;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readI64(int64_t& i64) {
|
||||
union bytes {
|
||||
uint8_t b[8];
|
||||
int64_t all;
|
||||
} theBytes;
|
||||
this->trans_->readAll(theBytes.b, 8);
|
||||
i64 = (int64_t)ntohll(theBytes.all);
|
||||
return 8;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readDouble(double& dub) {
|
||||
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
|
||||
|
||||
union bytes {
|
||||
uint8_t b[8];
|
||||
uint64_t all;
|
||||
} theBytes;
|
||||
this->trans_->readAll(theBytes.b, 8);
|
||||
theBytes.all = ntohll(theBytes.all);
|
||||
dub = bitwise_cast<double>(theBytes.all);
|
||||
return 8;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
template<typename StrType>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readString(StrType& str) {
|
||||
uint32_t result;
|
||||
int32_t size;
|
||||
result = readI32(size);
|
||||
return result + readStringBody(str, size);
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readBinary(std::string& str) {
|
||||
return TBinaryProtocolT<Transport_>::readString(str);
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
template<typename StrType>
|
||||
uint32_t TBinaryProtocolT<Transport_>::readStringBody(StrType& str,
|
||||
int32_t size) {
|
||||
uint32_t result = 0;
|
||||
|
||||
// Catch error cases
|
||||
if (size < 0) {
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
}
|
||||
if (this->string_limit_ > 0 && size > this->string_limit_) {
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
|
||||
// Catch empty string case
|
||||
if (size == 0) {
|
||||
str.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Try to borrow first
|
||||
const uint8_t* borrow_buf;
|
||||
uint32_t got = size;
|
||||
if ((borrow_buf = this->trans_->borrow(NULL, &got))) {
|
||||
str.assign((const char*)borrow_buf, size);
|
||||
this->trans_->consume(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
// Use the heap here to prevent stack overflow for v. large strings
|
||||
if (size > this->string_buf_size_ || this->string_buf_ == NULL) {
|
||||
void* new_string_buf = std::realloc(this->string_buf_, (uint32_t)size);
|
||||
if (new_string_buf == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
this->string_buf_ = (uint8_t*)new_string_buf;
|
||||
this->string_buf_size_ = size;
|
||||
}
|
||||
this->trans_->readAll(this->string_buf_, size);
|
||||
str.assign((char*)this->string_buf_, size);
|
||||
return (uint32_t)size;
|
||||
}
|
||||
|
||||
}}} // apache::thrift::protocol
|
||||
|
||||
#endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
|
|
@ -20,7 +20,7 @@
|
|||
#ifndef _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_
|
||||
#define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_ 1
|
||||
|
||||
#include "TProtocol.h"
|
||||
#include "TVirtualProtocol.h"
|
||||
|
||||
#include <stack>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
@ -30,15 +30,19 @@ namespace apache { namespace thrift { namespace protocol {
|
|||
/**
|
||||
* C++ Implementation of the Compact Protocol as described in THRIFT-110
|
||||
*/
|
||||
class TCompactProtocol : public TProtocol {
|
||||
template <class Transport_>
|
||||
class TCompactProtocolT
|
||||
: public TVirtualProtocol< TCompactProtocolT<Transport_> > {
|
||||
|
||||
protected:
|
||||
static const int8_t PROTOCOL_ID = 0x82;
|
||||
static const int8_t PROTOCOL_ID = (int8_t)0x82;
|
||||
static const int8_t VERSION_N = 1;
|
||||
static const int8_t VERSION_MASK = 0x1f; // 0001 1111
|
||||
static const int8_t TYPE_MASK = 0xE0; // 1110 0000
|
||||
static const int8_t TYPE_MASK = (int8_t)0xE0; // 1110 0000
|
||||
static const int32_t TYPE_SHIFT_AMOUNT = 5;
|
||||
|
||||
Transport_* trans_;
|
||||
|
||||
/**
|
||||
* (Writing) If we encounter a boolean field begin, save the TField here
|
||||
* so it can have the value incorporated.
|
||||
|
@ -66,27 +70,10 @@ class TCompactProtocol : public TProtocol {
|
|||
std::stack<int16_t> lastField_;
|
||||
int16_t lastFieldId_;
|
||||
|
||||
enum Types {
|
||||
CT_STOP = 0x00,
|
||||
CT_BOOLEAN_TRUE = 0x01,
|
||||
CT_BOOLEAN_FALSE = 0x02,
|
||||
CT_BYTE = 0x03,
|
||||
CT_I16 = 0x04,
|
||||
CT_I32 = 0x05,
|
||||
CT_I64 = 0x06,
|
||||
CT_DOUBLE = 0x07,
|
||||
CT_BINARY = 0x08,
|
||||
CT_LIST = 0x09,
|
||||
CT_SET = 0x0A,
|
||||
CT_MAP = 0x0B,
|
||||
CT_STRUCT = 0x0C,
|
||||
};
|
||||
|
||||
static const int8_t TTypeToCType[16];
|
||||
|
||||
public:
|
||||
TCompactProtocol(boost::shared_ptr<TTransport> trans) :
|
||||
TProtocol(trans),
|
||||
TCompactProtocolT(boost::shared_ptr<Transport_> trans) :
|
||||
TVirtualProtocol< TCompactProtocolT<Transport_> >(trans),
|
||||
trans_(trans.get()),
|
||||
lastFieldId_(0),
|
||||
string_limit_(0),
|
||||
string_buf_(NULL),
|
||||
|
@ -96,10 +83,11 @@ class TCompactProtocol : public TProtocol {
|
|||
boolValue_.hasBoolValue = false;
|
||||
}
|
||||
|
||||
TCompactProtocol(boost::shared_ptr<TTransport> trans,
|
||||
TCompactProtocolT(boost::shared_ptr<Transport_> trans,
|
||||
int32_t string_limit,
|
||||
int32_t container_limit) :
|
||||
TProtocol(trans),
|
||||
TVirtualProtocol< TCompactProtocolT<Transport_> >(trans),
|
||||
trans_(trans.get()),
|
||||
lastFieldId_(0),
|
||||
string_limit_(string_limit),
|
||||
string_buf_(NULL),
|
||||
|
@ -109,7 +97,7 @@ class TCompactProtocol : public TProtocol {
|
|||
boolValue_.hasBoolValue = false;
|
||||
}
|
||||
|
||||
~TCompactProtocol() {
|
||||
~TCompactProtocolT() {
|
||||
free(string_buf_);
|
||||
}
|
||||
|
||||
|
@ -204,6 +192,8 @@ class TCompactProtocol : public TProtocol {
|
|||
uint32_t& size);
|
||||
|
||||
uint32_t readBool(bool& value);
|
||||
// Provide the default readBool() implementation for std::vector<bool>
|
||||
using TVirtualProtocol< TCompactProtocolT<Transport_> >::readBool;
|
||||
|
||||
uint32_t readByte(int8_t& byte);
|
||||
|
||||
|
@ -244,20 +234,23 @@ class TCompactProtocol : public TProtocol {
|
|||
int32_t container_limit_;
|
||||
};
|
||||
|
||||
typedef TCompactProtocolT<TTransport> TCompactProtocol;
|
||||
|
||||
/**
|
||||
* Constructs compact protocol handlers
|
||||
*/
|
||||
class TCompactProtocolFactory : public TProtocolFactory {
|
||||
template <class Transport_>
|
||||
class TCompactProtocolFactoryT : public TProtocolFactory {
|
||||
public:
|
||||
TCompactProtocolFactory() :
|
||||
TCompactProtocolFactoryT() :
|
||||
string_limit_(0),
|
||||
container_limit_(0) {}
|
||||
|
||||
TCompactProtocolFactory(int32_t string_limit, int32_t container_limit) :
|
||||
TCompactProtocolFactoryT(int32_t string_limit, int32_t container_limit) :
|
||||
string_limit_(string_limit),
|
||||
container_limit_(container_limit) {}
|
||||
|
||||
virtual ~TCompactProtocolFactory() {}
|
||||
virtual ~TCompactProtocolFactoryT() {}
|
||||
|
||||
void setStringSizeLimit(int32_t string_limit) {
|
||||
string_limit_ = string_limit;
|
||||
|
@ -268,7 +261,17 @@ class TCompactProtocolFactory : public TProtocolFactory {
|
|||
}
|
||||
|
||||
boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
|
||||
return boost::shared_ptr<TProtocol>(new TCompactProtocol(trans, string_limit_, container_limit_));
|
||||
boost::shared_ptr<Transport_> specific_trans =
|
||||
boost::dynamic_pointer_cast<Transport_>(trans);
|
||||
TProtocol* prot;
|
||||
if (specific_trans) {
|
||||
prot = new TCompactProtocolT<Transport_>(specific_trans, string_limit_,
|
||||
container_limit_);
|
||||
} else {
|
||||
prot = new TCompactProtocol(trans, string_limit_, container_limit_);
|
||||
}
|
||||
|
||||
return boost::shared_ptr<TProtocol>(prot);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -277,6 +280,10 @@ class TCompactProtocolFactory : public TProtocolFactory {
|
|||
|
||||
};
|
||||
|
||||
typedef TCompactProtocolFactoryT<TTransport> TCompactProtocolFactory;
|
||||
|
||||
}}} // apache::thrift::protocol
|
||||
|
||||
#include "TCompactProtocol.tcc"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,811 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
#ifndef _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_
|
||||
#define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_ 1
|
||||
|
||||
#include <limits>
|
||||
|
||||
/*
|
||||
* TCompactProtocol::i*ToZigzag depend on the fact that the right shift
|
||||
* operator on a signed integer is an arithmetic (sign-extending) shift.
|
||||
* If this is not the case, the current implementation will not work.
|
||||
* If anyone encounters this error, we can try to figure out the best
|
||||
* way to implement an arithmetic right shift on their platform.
|
||||
*/
|
||||
#if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT)
|
||||
# error "Unable to determine the behavior of a signed right shift"
|
||||
#endif
|
||||
#if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT
|
||||
# error "TCompactProtocol currently only works if a signed right shift is arithmetic"
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UNLIKELY(val) (__builtin_expect((val), 0))
|
||||
#else
|
||||
#define UNLIKELY(val) (val)
|
||||
#endif
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
|
||||
namespace detail { namespace compact {
|
||||
|
||||
enum Types {
|
||||
CT_STOP = 0x00,
|
||||
CT_BOOLEAN_TRUE = 0x01,
|
||||
CT_BOOLEAN_FALSE = 0x02,
|
||||
CT_BYTE = 0x03,
|
||||
CT_I16 = 0x04,
|
||||
CT_I32 = 0x05,
|
||||
CT_I64 = 0x06,
|
||||
CT_DOUBLE = 0x07,
|
||||
CT_BINARY = 0x08,
|
||||
CT_LIST = 0x09,
|
||||
CT_SET = 0x0A,
|
||||
CT_MAP = 0x0B,
|
||||
CT_STRUCT = 0x0C
|
||||
};
|
||||
|
||||
const int8_t TTypeToCType[16] = {
|
||||
CT_STOP, // T_STOP
|
||||
0, // unused
|
||||
CT_BOOLEAN_TRUE, // T_BOOL
|
||||
CT_BYTE, // T_BYTE
|
||||
CT_DOUBLE, // T_DOUBLE
|
||||
0, // unused
|
||||
CT_I16, // T_I16
|
||||
0, // unused
|
||||
CT_I32, // T_I32
|
||||
0, // unused
|
||||
CT_I64, // T_I64
|
||||
CT_BINARY, // T_STRING
|
||||
CT_STRUCT, // T_STRUCT
|
||||
CT_MAP, // T_MAP
|
||||
CT_SET, // T_SET
|
||||
CT_LIST, // T_LIST
|
||||
};
|
||||
|
||||
}} // end detail::compact namespace
|
||||
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeMessageBegin(
|
||||
const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) {
|
||||
uint32_t wsize = 0;
|
||||
wsize += writeByte(PROTOCOL_ID);
|
||||
wsize += writeByte((VERSION_N & VERSION_MASK) | (((int32_t)messageType << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
|
||||
wsize += writeVarint32(seqid);
|
||||
wsize += writeString(name);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a field header containing the field id and field type. If the
|
||||
* difference between the current field id and the last one is small (< 15),
|
||||
* then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
|
||||
* field id will follow the type header as a zigzag varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) {
|
||||
if (fieldType == T_BOOL) {
|
||||
booleanField_.name = name;
|
||||
booleanField_.fieldType = fieldType;
|
||||
booleanField_.fieldId = fieldId;
|
||||
} else {
|
||||
return writeFieldBeginInternal(name, fieldType, fieldId, -1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the STOP symbol so we know there are no more fields in this struct.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeFieldStop() {
|
||||
return writeByte(T_STOP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a struct begin. This doesn't actually put anything on the wire. We
|
||||
* use it as an opportunity to put special placeholder markers on the field
|
||||
* stack so we can get the field id deltas correct.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeStructBegin(const char* name) {
|
||||
(void) name;
|
||||
lastField_.push(lastFieldId_);
|
||||
lastFieldId_ = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a struct end. This doesn't actually put anything on the wire. We use
|
||||
* this as an opportunity to pop the last field from the current struct off
|
||||
* of the field stack.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeStructEnd() {
|
||||
lastFieldId_ = lastField_.top();
|
||||
lastField_.pop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a List header.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeListBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
return writeCollectionBegin(elemType, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a set header.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeSetBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
return writeCollectionBegin(elemType, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a map header. If the map is empty, omit the key and value type
|
||||
* headers, as we don't need any additional information to skip it.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) {
|
||||
uint32_t wsize = 0;
|
||||
|
||||
if (size == 0) {
|
||||
wsize += writeByte(0);
|
||||
} else {
|
||||
wsize += writeVarint32(size);
|
||||
wsize += writeByte(getCompactType(keyType) << 4 | getCompactType(valType));
|
||||
}
|
||||
return wsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a boolean value. Potentially, this could be a boolean field, in
|
||||
* which case the field header info isn't written yet. If so, decide what the
|
||||
* right type header is for the value and then write the field header.
|
||||
* Otherwise, write a single byte.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeBool(const bool value) {
|
||||
uint32_t wsize = 0;
|
||||
|
||||
if (booleanField_.name != NULL) {
|
||||
// we haven't written the field header yet
|
||||
wsize += writeFieldBeginInternal(booleanField_.name,
|
||||
booleanField_.fieldType,
|
||||
booleanField_.fieldId,
|
||||
value ? detail::compact::CT_BOOLEAN_TRUE :
|
||||
detail::compact::CT_BOOLEAN_FALSE);
|
||||
booleanField_.name = NULL;
|
||||
} else {
|
||||
// we're not part of a field, so just write the value
|
||||
wsize += writeByte(value ? detail::compact::CT_BOOLEAN_TRUE :
|
||||
detail::compact::CT_BOOLEAN_FALSE);
|
||||
}
|
||||
return wsize;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeByte(const int8_t byte) {
|
||||
trans_->write((uint8_t*)&byte, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an i16 as a zigzag varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeI16(const int16_t i16) {
|
||||
return writeVarint32(i32ToZigzag(i16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an i32 as a zigzag varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeI32(const int32_t i32) {
|
||||
return writeVarint32(i32ToZigzag(i32));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an i64 as a zigzag varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeI64(const int64_t i64) {
|
||||
return writeVarint64(i64ToZigzag(i64));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a double to the wire as 8 bytes.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeDouble(const double dub) {
|
||||
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
|
||||
|
||||
uint64_t bits = bitwise_cast<uint64_t>(dub);
|
||||
bits = htolell(bits);
|
||||
trans_->write((uint8_t*)&bits, 8);
|
||||
return 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a string to the wire with a varint size preceeding.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeString(const std::string& str) {
|
||||
return writeBinary(str);
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeBinary(const std::string& str) {
|
||||
uint32_t ssize = str.size();
|
||||
uint32_t wsize = writeVarint32(ssize) + ssize;
|
||||
trans_->write((uint8_t*)str.data(), ssize);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
//
|
||||
// Internal Writing methods
|
||||
//
|
||||
|
||||
/**
|
||||
* The workhorse of writeFieldBegin. It has the option of doing a
|
||||
* 'type override' of the type header. This is used specifically in the
|
||||
* boolean field case.
|
||||
*/
|
||||
template <class Transport_>
|
||||
int32_t TCompactProtocolT<Transport_>::writeFieldBeginInternal(
|
||||
const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId,
|
||||
int8_t typeOverride) {
|
||||
(void) name;
|
||||
uint32_t wsize = 0;
|
||||
|
||||
// if there's a type override, use that.
|
||||
int8_t typeToWrite = (typeOverride == -1 ? getCompactType(fieldType) : typeOverride);
|
||||
|
||||
// check if we can use delta encoding for the field id
|
||||
if (fieldId > lastFieldId_ && fieldId - lastFieldId_ <= 15) {
|
||||
// write them together
|
||||
wsize += writeByte((fieldId - lastFieldId_) << 4 | typeToWrite);
|
||||
} else {
|
||||
// write them separate
|
||||
wsize += writeByte(typeToWrite);
|
||||
wsize += writeI16(fieldId);
|
||||
}
|
||||
|
||||
lastFieldId_ = fieldId;
|
||||
return wsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method for writing the start of lists and sets. List and sets on
|
||||
* the wire differ only by the type indicator.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeCollectionBegin(int8_t elemType,
|
||||
int32_t size) {
|
||||
uint32_t wsize = 0;
|
||||
if (size <= 14) {
|
||||
wsize += writeByte(size << 4 | getCompactType(elemType));
|
||||
} else {
|
||||
wsize += writeByte(0xf0 | getCompactType(elemType));
|
||||
wsize += writeVarint32(size);
|
||||
}
|
||||
return wsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an i32 as a varint. Results in 1-5 bytes on the wire.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeVarint32(uint32_t n) {
|
||||
uint8_t buf[5];
|
||||
uint32_t wsize = 0;
|
||||
|
||||
while (true) {
|
||||
if ((n & ~0x7F) == 0) {
|
||||
buf[wsize++] = (int8_t)n;
|
||||
break;
|
||||
} else {
|
||||
buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
|
||||
n >>= 7;
|
||||
}
|
||||
}
|
||||
trans_->write(buf, wsize);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an i64 as a varint. Results in 1-10 bytes on the wire.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::writeVarint64(uint64_t n) {
|
||||
uint8_t buf[10];
|
||||
uint32_t wsize = 0;
|
||||
|
||||
while (true) {
|
||||
if ((n & ~0x7FL) == 0) {
|
||||
buf[wsize++] = (int8_t)n;
|
||||
break;
|
||||
} else {
|
||||
buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
|
||||
n >>= 7;
|
||||
}
|
||||
}
|
||||
trans_->write(buf, wsize);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert l into a zigzag long. This allows negative numbers to be
|
||||
* represented compactly as a varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint64_t TCompactProtocolT<Transport_>::i64ToZigzag(const int64_t l) {
|
||||
return (l << 1) ^ (l >> 63);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert n into a zigzag int. This allows negative numbers to be
|
||||
* represented compactly as a varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::i32ToZigzag(const int32_t n) {
|
||||
return (n << 1) ^ (n >> 31);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a TType value, find the appropriate detail::compact::Types value
|
||||
*/
|
||||
template <class Transport_>
|
||||
int8_t TCompactProtocolT<Transport_>::getCompactType(int8_t ttype) {
|
||||
return detail::compact::TTypeToCType[ttype];
|
||||
}
|
||||
|
||||
//
|
||||
// Reading Methods
|
||||
//
|
||||
|
||||
/**
|
||||
* Read a message header.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readMessageBegin(
|
||||
std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) {
|
||||
uint32_t rsize = 0;
|
||||
int8_t protocolId;
|
||||
int8_t versionAndType;
|
||||
int8_t version;
|
||||
|
||||
rsize += readByte(protocolId);
|
||||
if (protocolId != PROTOCOL_ID) {
|
||||
throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol identifier");
|
||||
}
|
||||
|
||||
rsize += readByte(versionAndType);
|
||||
version = (int8_t)(versionAndType & VERSION_MASK);
|
||||
if (version != VERSION_N) {
|
||||
throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol version");
|
||||
}
|
||||
|
||||
messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
|
||||
rsize += readVarint32(seqid);
|
||||
rsize += readString(name);
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a struct begin. There's nothing on the wire for this, but it is our
|
||||
* opportunity to push a new struct begin marker on the field stack.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readStructBegin(std::string& name) {
|
||||
name = "";
|
||||
lastField_.push(lastFieldId_);
|
||||
lastFieldId_ = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Doesn't actually consume any wire data, just removes the last field for
|
||||
* this struct from the field stack.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readStructEnd() {
|
||||
lastFieldId_ = lastField_.top();
|
||||
lastField_.pop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a field header off the wire.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readFieldBegin(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) {
|
||||
(void) name;
|
||||
uint32_t rsize = 0;
|
||||
int8_t byte;
|
||||
int8_t type;
|
||||
|
||||
rsize += readByte(byte);
|
||||
type = (byte & 0x0f);
|
||||
|
||||
// if it's a stop, then we can return immediately, as the struct is over.
|
||||
if (type == T_STOP) {
|
||||
fieldType = T_STOP;
|
||||
fieldId = 0;
|
||||
return rsize;
|
||||
}
|
||||
|
||||
// mask off the 4 MSB of the type header. it could contain a field id delta.
|
||||
int16_t modifier = (int16_t)(((uint8_t)byte & 0xf0) >> 4);
|
||||
if (modifier == 0) {
|
||||
// not a delta, look ahead for the zigzag varint field id.
|
||||
rsize += readI16(fieldId);
|
||||
} else {
|
||||
fieldId = (int16_t)(lastFieldId_ + modifier);
|
||||
}
|
||||
fieldType = getTType(type);
|
||||
|
||||
// if this happens to be a boolean field, the value is encoded in the type
|
||||
if (type == detail::compact::CT_BOOLEAN_TRUE ||
|
||||
type == detail::compact::CT_BOOLEAN_FALSE) {
|
||||
// save the boolean value in a special instance variable.
|
||||
boolValue_.hasBoolValue = true;
|
||||
boolValue_.boolValue =
|
||||
(type == detail::compact::CT_BOOLEAN_TRUE ? true : false);
|
||||
}
|
||||
|
||||
// push the new field onto the field stack so we can keep the deltas going.
|
||||
lastFieldId_ = fieldId;
|
||||
return rsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a map header off the wire. If the size is zero, skip reading the key
|
||||
* and value type. This means that 0-length maps will yield TMaps without the
|
||||
* "correct" types.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readMapBegin(TType& keyType,
|
||||
TType& valType,
|
||||
uint32_t& size) {
|
||||
uint32_t rsize = 0;
|
||||
int8_t kvType = 0;
|
||||
int32_t msize = 0;
|
||||
|
||||
rsize += readVarint32(msize);
|
||||
if (msize != 0)
|
||||
rsize += readByte(kvType);
|
||||
|
||||
if (msize < 0) {
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
} else if (container_limit_ && msize > container_limit_) {
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
|
||||
keyType = getTType((int8_t)((uint8_t)kvType >> 4));
|
||||
valType = getTType((int8_t)((uint8_t)kvType & 0xf));
|
||||
size = (uint32_t)msize;
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a list header off the wire. If the list size is 0-14, the size will
|
||||
* be packed into the element type header. If it's a longer list, the 4 MSB
|
||||
* of the element type header will be 0xF, and a varint will follow with the
|
||||
* true size.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readListBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
int8_t size_and_type;
|
||||
uint32_t rsize = 0;
|
||||
int32_t lsize;
|
||||
|
||||
rsize += readByte(size_and_type);
|
||||
|
||||
lsize = ((uint8_t)size_and_type >> 4) & 0x0f;
|
||||
if (lsize == 15) {
|
||||
rsize += readVarint32(lsize);
|
||||
}
|
||||
|
||||
if (lsize < 0) {
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
} else if (container_limit_ && lsize > container_limit_) {
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
|
||||
elemType = getTType((int8_t)(size_and_type & 0x0f));
|
||||
size = (uint32_t)lsize;
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a set header off the wire. If the set size is 0-14, the size will
|
||||
* be packed into the element type header. If it's a longer set, the 4 MSB
|
||||
* of the element type header will be 0xF, and a varint will follow with the
|
||||
* true size.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readSetBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
return readListBegin(elemType, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a boolean off the wire. If this is a boolean field, the value should
|
||||
* already have been read during readFieldBegin, so we'll just consume the
|
||||
* pre-stored value. Otherwise, read a byte.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readBool(bool& value) {
|
||||
if (boolValue_.hasBoolValue == true) {
|
||||
value = boolValue_.boolValue;
|
||||
boolValue_.hasBoolValue = false;
|
||||
return 0;
|
||||
} else {
|
||||
int8_t val;
|
||||
readByte(val);
|
||||
value = (val == detail::compact::CT_BOOLEAN_TRUE);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single byte off the wire. Nothing interesting here.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readByte(int8_t& byte) {
|
||||
uint8_t b[1];
|
||||
trans_->readAll(b, 1);
|
||||
byte = *(int8_t*)b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an i16 from the wire as a zigzag varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readI16(int16_t& i16) {
|
||||
int32_t value;
|
||||
uint32_t rsize = readVarint32(value);
|
||||
i16 = (int16_t)zigzagToI32(value);
|
||||
return rsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an i32 from the wire as a zigzag varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readI32(int32_t& i32) {
|
||||
int32_t value;
|
||||
uint32_t rsize = readVarint32(value);
|
||||
i32 = zigzagToI32(value);
|
||||
return rsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an i64 from the wire as a zigzag varint.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readI64(int64_t& i64) {
|
||||
int64_t value;
|
||||
uint32_t rsize = readVarint64(value);
|
||||
i64 = zigzagToI64(value);
|
||||
return rsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* No magic here - just read a double off the wire.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readDouble(double& dub) {
|
||||
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
|
||||
|
||||
uint64_t bits;
|
||||
uint8_t b[8];
|
||||
trans_->readAll(b, 8);
|
||||
bits = *(uint64_t*)b;
|
||||
bits = letohll(bits);
|
||||
dub = bitwise_cast<double>(bits);
|
||||
return 8;
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readString(std::string& str) {
|
||||
return readBinary(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte[] from the wire.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readBinary(std::string& str) {
|
||||
int32_t rsize = 0;
|
||||
int32_t size;
|
||||
|
||||
rsize += readVarint32(size);
|
||||
// Catch empty string case
|
||||
if (size == 0) {
|
||||
str = "";
|
||||
return rsize;
|
||||
}
|
||||
|
||||
// Catch error cases
|
||||
if (size < 0) {
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
}
|
||||
if (string_limit_ > 0 && size > string_limit_) {
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
|
||||
// Use the heap here to prevent stack overflow for v. large strings
|
||||
if (size > string_buf_size_ || string_buf_ == NULL) {
|
||||
void* new_string_buf = std::realloc(string_buf_, (uint32_t)size);
|
||||
if (new_string_buf == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
string_buf_ = (uint8_t*)new_string_buf;
|
||||
string_buf_size_ = size;
|
||||
}
|
||||
trans_->readAll(string_buf_, size);
|
||||
str.assign((char*)string_buf_, size);
|
||||
|
||||
return rsize + (uint32_t)size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an i32 from the wire as a varint. The MSB of each byte is set
|
||||
* if there is another byte to follow. This can read up to 5 bytes.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readVarint32(int32_t& i32) {
|
||||
int64_t val;
|
||||
uint32_t rsize = readVarint64(val);
|
||||
i32 = (int32_t)val;
|
||||
return rsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an i64 from the wire as a proper varint. The MSB of each byte is set
|
||||
* if there is another byte to follow. This can read up to 10 bytes.
|
||||
*/
|
||||
template <class Transport_>
|
||||
uint32_t TCompactProtocolT<Transport_>::readVarint64(int64_t& i64) {
|
||||
uint32_t rsize = 0;
|
||||
uint64_t val = 0;
|
||||
int shift = 0;
|
||||
uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
|
||||
uint32_t buf_size = sizeof(buf);
|
||||
const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
|
||||
|
||||
// Fast path.
|
||||
if (borrowed != NULL) {
|
||||
while (true) {
|
||||
uint8_t byte = borrowed[rsize];
|
||||
rsize++;
|
||||
val |= (uint64_t)(byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
if (!(byte & 0x80)) {
|
||||
i64 = val;
|
||||
trans_->consume(rsize);
|
||||
return rsize;
|
||||
}
|
||||
// Have to check for invalid data so we don't crash.
|
||||
if (UNLIKELY(rsize == sizeof(buf))) {
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Slow path.
|
||||
else {
|
||||
while (true) {
|
||||
uint8_t byte;
|
||||
rsize += trans_->readAll(&byte, 1);
|
||||
val |= (uint64_t)(byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
if (!(byte & 0x80)) {
|
||||
i64 = val;
|
||||
return rsize;
|
||||
}
|
||||
// Might as well check for invalid data on the slow path too.
|
||||
if (UNLIKELY(rsize >= sizeof(buf))) {
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from zigzag int to int.
|
||||
*/
|
||||
template <class Transport_>
|
||||
int32_t TCompactProtocolT<Transport_>::zigzagToI32(uint32_t n) {
|
||||
return (n >> 1) ^ -(n & 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from zigzag long to long.
|
||||
*/
|
||||
template <class Transport_>
|
||||
int64_t TCompactProtocolT<Transport_>::zigzagToI64(uint64_t n) {
|
||||
return (n >> 1) ^ -(n & 1);
|
||||
}
|
||||
|
||||
template <class Transport_>
|
||||
TType TCompactProtocolT<Transport_>::getTType(int8_t type) {
|
||||
switch (type) {
|
||||
case T_STOP:
|
||||
return T_STOP;
|
||||
case detail::compact::CT_BOOLEAN_FALSE:
|
||||
case detail::compact::CT_BOOLEAN_TRUE:
|
||||
return T_BOOL;
|
||||
case detail::compact::CT_BYTE:
|
||||
return T_BYTE;
|
||||
case detail::compact::CT_I16:
|
||||
return T_I16;
|
||||
case detail::compact::CT_I32:
|
||||
return T_I32;
|
||||
case detail::compact::CT_I64:
|
||||
return T_I64;
|
||||
case detail::compact::CT_DOUBLE:
|
||||
return T_DOUBLE;
|
||||
case detail::compact::CT_BINARY:
|
||||
return T_STRING;
|
||||
case detail::compact::CT_LIST:
|
||||
return T_LIST;
|
||||
case detail::compact::CT_SET:
|
||||
return T_SET;
|
||||
case detail::compact::CT_MAP:
|
||||
return T_MAP;
|
||||
case detail::compact::CT_STRUCT:
|
||||
return T_STRUCT;
|
||||
default:
|
||||
throw TException("don't know what type: " + type);
|
||||
}
|
||||
return T_STOP;
|
||||
}
|
||||
|
||||
}}} // apache::thrift::protocol
|
||||
|
||||
#endif // _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_
|
358
nativeLib/org.apache.thrift/include/protocol/TDebugProtocol.cpp
Normal file
358
nativeLib/org.apache.thrift/include/protocol/TDebugProtocol.cpp
Normal file
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "TDebugProtocol.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
static string byte_to_hex(const uint8_t byte) {
|
||||
char buf[3];
|
||||
int ret = std::sprintf(buf, "%02x", (int)byte);
|
||||
ret = ret; //squelching "unused variable" warning
|
||||
assert(ret == 2);
|
||||
assert(buf[2] == '\0');
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
|
||||
string TDebugProtocol::fieldTypeName(TType type) {
|
||||
switch (type) {
|
||||
case T_STOP : return "stop" ;
|
||||
case T_VOID : return "void" ;
|
||||
case T_BOOL : return "bool" ;
|
||||
case T_BYTE : return "byte" ;
|
||||
case T_I16 : return "i16" ;
|
||||
case T_I32 : return "i32" ;
|
||||
case T_U64 : return "u64" ;
|
||||
case T_I64 : return "i64" ;
|
||||
case T_DOUBLE : return "double" ;
|
||||
case T_STRING : return "string" ;
|
||||
case T_STRUCT : return "struct" ;
|
||||
case T_MAP : return "map" ;
|
||||
case T_SET : return "set" ;
|
||||
case T_LIST : return "list" ;
|
||||
case T_UTF8 : return "utf8" ;
|
||||
case T_UTF16 : return "utf16" ;
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void TDebugProtocol::indentUp() {
|
||||
indent_str_ += string(indent_inc, ' ');
|
||||
}
|
||||
|
||||
void TDebugProtocol::indentDown() {
|
||||
if (indent_str_.length() < (string::size_type)indent_inc) {
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA);
|
||||
}
|
||||
indent_str_.erase(indent_str_.length() - indent_inc);
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writePlain(const string& str) {
|
||||
if(str.length() > (std::numeric_limits<uint32_t>::max)())
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
trans_->write((uint8_t*)str.data(), static_cast<uint32_t>(str.length()));
|
||||
return static_cast<uint32_t>(str.length());
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeIndented(const string& str) {
|
||||
if(str.length() > (std::numeric_limits<uint32_t>::max)())
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
if(indent_str_.length() > (std::numeric_limits<uint32_t>::max)())
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
uint64_t total_len = indent_str_.length() + str.length();
|
||||
if(total_len > (std::numeric_limits<uint32_t>::max)())
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
trans_->write((uint8_t*)indent_str_.data(), static_cast<uint32_t>(indent_str_.length()));
|
||||
trans_->write((uint8_t*)str.data(), static_cast<uint32_t>(str.length()));
|
||||
return static_cast<uint32_t>(indent_str_.length() + str.length());
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::startItem() {
|
||||
uint32_t size;
|
||||
|
||||
switch (write_state_.back()) {
|
||||
case UNINIT:
|
||||
// XXX figure out what to do here.
|
||||
//throw TProtocolException(TProtocolException::INVALID_DATA);
|
||||
//return writeIndented(str);
|
||||
return 0;
|
||||
case STRUCT:
|
||||
return 0;
|
||||
case SET:
|
||||
return writeIndented("");
|
||||
case MAP_KEY:
|
||||
return writeIndented("");
|
||||
case MAP_VALUE:
|
||||
return writePlain(" -> ");
|
||||
case LIST:
|
||||
size = writeIndented(
|
||||
"[" + boost::lexical_cast<string>(list_idx_.back()) + "] = ");
|
||||
list_idx_.back()++;
|
||||
return size;
|
||||
default:
|
||||
throw std::logic_error("Invalid enum value.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::endItem() {
|
||||
//uint32_t size;
|
||||
|
||||
switch (write_state_.back()) {
|
||||
case UNINIT:
|
||||
// XXX figure out what to do here.
|
||||
//throw TProtocolException(TProtocolException::INVALID_DATA);
|
||||
//return writeIndented(str);
|
||||
return 0;
|
||||
case STRUCT:
|
||||
return writePlain(",\n");
|
||||
case SET:
|
||||
return writePlain(",\n");
|
||||
case MAP_KEY:
|
||||
write_state_.back() = MAP_VALUE;
|
||||
return 0;
|
||||
case MAP_VALUE:
|
||||
write_state_.back() = MAP_KEY;
|
||||
return writePlain(",\n");
|
||||
case LIST:
|
||||
return writePlain(",\n");
|
||||
default:
|
||||
throw std::logic_error("Invalid enum value.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeItem(const std::string& str) {
|
||||
uint32_t size = 0;
|
||||
size += startItem();
|
||||
size += writePlain(str);
|
||||
size += endItem();
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) {
|
||||
(void) seqid;
|
||||
string mtype;
|
||||
switch (messageType) {
|
||||
case T_CALL : mtype = "call" ; break;
|
||||
case T_REPLY : mtype = "reply" ; break;
|
||||
case T_EXCEPTION : mtype = "exn" ; break;
|
||||
case T_ONEWAY : mtype = "oneway" ; break;
|
||||
}
|
||||
|
||||
uint32_t size = writeIndented("(" + mtype + ") " + name + "(");
|
||||
indentUp();
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeMessageEnd() {
|
||||
indentDown();
|
||||
return writeIndented(")\n");
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeStructBegin(const char* name) {
|
||||
uint32_t size = 0;
|
||||
size += startItem();
|
||||
size += writePlain(string(name) + " {\n");
|
||||
indentUp();
|
||||
write_state_.push_back(STRUCT);
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeStructEnd() {
|
||||
indentDown();
|
||||
write_state_.pop_back();
|
||||
uint32_t size = 0;
|
||||
size += writeIndented("}");
|
||||
size += endItem();
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) {
|
||||
// sprintf(id_str, "%02d", fieldId);
|
||||
string id_str = boost::lexical_cast<string>(fieldId);
|
||||
if (id_str.length() == 1) id_str = '0' + id_str;
|
||||
|
||||
return writeIndented(
|
||||
id_str + ": " +
|
||||
name + " (" +
|
||||
fieldTypeName(fieldType) + ") = ");
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeFieldEnd() {
|
||||
assert(write_state_.back() == STRUCT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeFieldStop() {
|
||||
return 0;
|
||||
//writeIndented("***STOP***\n");
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) {
|
||||
// TODO(dreiss): Optimize short maps?
|
||||
uint32_t bsize = 0;
|
||||
bsize += startItem();
|
||||
bsize += writePlain(
|
||||
"map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
|
||||
"[" + boost::lexical_cast<string>(size) + "] {\n");
|
||||
indentUp();
|
||||
write_state_.push_back(MAP_KEY);
|
||||
return bsize;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeMapEnd() {
|
||||
indentDown();
|
||||
write_state_.pop_back();
|
||||
uint32_t size = 0;
|
||||
size += writeIndented("}");
|
||||
size += endItem();
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeListBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
// TODO(dreiss): Optimize short arrays.
|
||||
uint32_t bsize = 0;
|
||||
bsize += startItem();
|
||||
bsize += writePlain(
|
||||
"list<" + fieldTypeName(elemType) + ">"
|
||||
"[" + boost::lexical_cast<string>(size) + "] {\n");
|
||||
indentUp();
|
||||
write_state_.push_back(LIST);
|
||||
list_idx_.push_back(0);
|
||||
return bsize;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeListEnd() {
|
||||
indentDown();
|
||||
write_state_.pop_back();
|
||||
list_idx_.pop_back();
|
||||
uint32_t size = 0;
|
||||
size += writeIndented("}");
|
||||
size += endItem();
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeSetBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
// TODO(dreiss): Optimize short sets.
|
||||
uint32_t bsize = 0;
|
||||
bsize += startItem();
|
||||
bsize += writePlain(
|
||||
"set<" + fieldTypeName(elemType) + ">"
|
||||
"[" + boost::lexical_cast<string>(size) + "] {\n");
|
||||
indentUp();
|
||||
write_state_.push_back(SET);
|
||||
return bsize;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeSetEnd() {
|
||||
indentDown();
|
||||
write_state_.pop_back();
|
||||
uint32_t size = 0;
|
||||
size += writeIndented("}");
|
||||
size += endItem();
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeBool(const bool value) {
|
||||
return writeItem(value ? "true" : "false");
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeByte(const int8_t byte) {
|
||||
return writeItem("0x" + byte_to_hex(byte));
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeI16(const int16_t i16) {
|
||||
return writeItem(boost::lexical_cast<string>(i16));
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeI32(const int32_t i32) {
|
||||
return writeItem(boost::lexical_cast<string>(i32));
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeI64(const int64_t i64) {
|
||||
return writeItem(boost::lexical_cast<string>(i64));
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeDouble(const double dub) {
|
||||
return writeItem(boost::lexical_cast<string>(dub));
|
||||
}
|
||||
|
||||
|
||||
uint32_t TDebugProtocol::writeString(const string& str) {
|
||||
// XXX Raw/UTF-8?
|
||||
|
||||
string to_show = str;
|
||||
if (to_show.length() > (string::size_type)string_limit_) {
|
||||
to_show = str.substr(0, string_prefix_size_);
|
||||
to_show += "[...](" + boost::lexical_cast<string>(str.length()) + ")";
|
||||
}
|
||||
|
||||
string output = "\"";
|
||||
|
||||
for (string::const_iterator it = to_show.begin(); it != to_show.end(); ++it) {
|
||||
if (*it == '\\') {
|
||||
output += "\\\\";
|
||||
} else if (*it == '"') {
|
||||
output += "\\\"";
|
||||
} else if (std::isprint(*it)) {
|
||||
output += *it;
|
||||
} else {
|
||||
switch (*it) {
|
||||
case '\a': output += "\\a"; break;
|
||||
case '\b': output += "\\b"; break;
|
||||
case '\f': output += "\\f"; break;
|
||||
case '\n': output += "\\n"; break;
|
||||
case '\r': output += "\\r"; break;
|
||||
case '\t': output += "\\t"; break;
|
||||
case '\v': output += "\\v"; break;
|
||||
default:
|
||||
output += "\\x";
|
||||
output += byte_to_hex(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output += '\"';
|
||||
return writeItem(output);
|
||||
}
|
||||
|
||||
uint32_t TDebugProtocol::writeBinary(const string& str) {
|
||||
// XXX Hex?
|
||||
return TDebugProtocol::writeString(str);
|
||||
}
|
||||
|
||||
}}} // apache::thrift::protocol
|
|
@ -20,8 +20,7 @@
|
|||
#ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_
|
||||
#define _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ 1
|
||||
|
||||
#include "TProtocol.h"
|
||||
#include "TOneWayProtocol.h"
|
||||
#include "TVirtualProtocol.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
@ -46,7 +45,7 @@ Complaints are not. :R
|
|||
* Reading from this protocol is not supported.
|
||||
*
|
||||
*/
|
||||
class TDebugProtocol : public TWriteOnlyProtocol {
|
||||
class TDebugProtocol : public TVirtualProtocol<TDebugProtocol> {
|
||||
private:
|
||||
enum write_state_t
|
||||
{ UNINIT
|
||||
|
@ -59,7 +58,8 @@ class TDebugProtocol : public TWriteOnlyProtocol {
|
|||
|
||||
public:
|
||||
TDebugProtocol(boost::shared_ptr<TTransport> trans)
|
||||
: TWriteOnlyProtocol(trans, "TDebugProtocol")
|
||||
: TVirtualProtocol<TDebugProtocol>(trans)
|
||||
, trans_(trans.get())
|
||||
, string_limit_(DEFAULT_STRING_LIMIT)
|
||||
, string_prefix_size_(DEFAULT_STRING_PREFIX_SIZE)
|
||||
{
|
||||
|
@ -78,11 +78,11 @@ class TDebugProtocol : public TWriteOnlyProtocol {
|
|||
}
|
||||
|
||||
|
||||
virtual uint32_t writeMessageBegin(const std::string& name,
|
||||
uint32_t writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid);
|
||||
|
||||
virtual uint32_t writeMessageEnd();
|
||||
uint32_t writeMessageEnd();
|
||||
|
||||
|
||||
uint32_t writeStructBegin(const char* name);
|
||||
|
@ -141,6 +141,8 @@ class TDebugProtocol : public TWriteOnlyProtocol {
|
|||
|
||||
static std::string fieldTypeName(TType type);
|
||||
|
||||
TTransport* trans_;
|
||||
|
||||
int32_t string_limit_;
|
||||
int32_t string_prefix_size_;
|
||||
|
||||
|
@ -169,7 +171,7 @@ class TDebugProtocolFactory : public TProtocolFactory {
|
|||
|
||||
|
||||
// TODO(dreiss): Move (part of) ThriftDebugString into a .cpp file and remove this.
|
||||
#include <transport/TBufferTransports.h>
|
||||
#include <thrift/transport/TBufferTransports.h>
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
||||
|
|
768
nativeLib/org.apache.thrift/include/protocol/TDenseProtocol.cpp
Normal file
768
nativeLib/org.apache.thrift/include/protocol/TDenseProtocol.cpp
Normal file
|
@ -0,0 +1,768 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
IMPLEMENTATION DETAILS
|
||||
|
||||
TDenseProtocol was designed to have a smaller serialized form than
|
||||
TBinaryProtocol. This is accomplished using two techniques. The first is
|
||||
variable-length integer encoding. We use the same technique that the Standard
|
||||
MIDI File format uses for "variable-length quantities"
|
||||
(http://en.wikipedia.org/wiki/Variable-length_quantity).
|
||||
All integers (including i16, but not byte) are first cast to uint64_t,
|
||||
then written out as variable-length quantities. This has the unfortunate side
|
||||
effect that all negative numbers require 10 bytes, but negative numbers tend
|
||||
to be far less common than positive ones.
|
||||
|
||||
The second technique eliminating the field ids used by TBinaryProtocol. This
|
||||
decision required support from the Thrift compiler and also sacrifices some of
|
||||
the backward and forward compatibility of TBinaryProtocol.
|
||||
|
||||
We considered implementing this technique by generating separate readers and
|
||||
writers for the dense protocol (this is how Pillar, Thrift's predecessor,
|
||||
worked), but this idea had a few problems:
|
||||
- Our abstractions go out the window.
|
||||
- We would have to maintain a second code generator.
|
||||
- Preserving compatibility with old versions of the structures would be a
|
||||
nightmare.
|
||||
|
||||
Therefore, we chose an alternate implementation that stored the description of
|
||||
the data neither in the data itself (like TBinaryProtocol) nor in the
|
||||
serialization code (like Pillar), but instead in a separate data structure,
|
||||
called a TypeSpec. TypeSpecs are generated by the Thrift compiler
|
||||
(specifically in the t_cpp_generator), and their structure should be
|
||||
documented there (TODO(dreiss): s/should be/is/).
|
||||
|
||||
We maintain a stack of TypeSpecs within the protocol so it knows where the
|
||||
generated code is in the reading/writing process. For example, if we are
|
||||
writing an i32 contained in a struct bar, contained in a struct foo, then the
|
||||
stack would look like: TOP , i32 , struct bar , struct foo , BOTTOM.
|
||||
The following invariant: whenever we are about to read/write an object
|
||||
(structBegin, containerBegin, or a scalar), the TypeSpec on the top of the
|
||||
stack must match the type being read/written. The main reasons that this
|
||||
invariant must be maintained is that if we ever start reading a structure, we
|
||||
must have its exact TypeSpec in order to pass the right tags to the
|
||||
deserializer.
|
||||
|
||||
We use the following strategies for maintaining this invariant:
|
||||
|
||||
- For structures, we have a separate stack of indexes, one for each structure
|
||||
on the TypeSpec stack. These are indexes into the list of fields in the
|
||||
structure's TypeSpec. When we {read,write}FieldBegin, we push on the
|
||||
TypeSpec for the field.
|
||||
- When we begin writing a list or set, we push on the TypeSpec for the
|
||||
element type.
|
||||
- For maps, we have a separate stack of booleans, one for each map on the
|
||||
TypeSpec stack. The boolean is true if we are writing the key for that
|
||||
map, and false if we are writing the value. Maps are the trickiest case
|
||||
because the generated code does not call any protocol method between
|
||||
the key and the value. As a result, we potentially have to switch
|
||||
between map key state and map value state after reading/writing any object.
|
||||
- This job is handled by the stateTransition method. It is called after
|
||||
reading/writing every object. It pops the current TypeSpec off the stack,
|
||||
then optionally pushes a new one on, depending on what the next TypeSpec is.
|
||||
If it is a struct, the job is left to the next writeFieldBegin. If it is a
|
||||
set or list, the just-popped typespec is pushed back on. If it is a map,
|
||||
the top of the key/value stack is toggled, and the appropriate TypeSpec
|
||||
is pushed.
|
||||
|
||||
Optional fields are a little tricky also. We write a zero byte if they are
|
||||
absent and prefix them with an 0x01 byte if they are present
|
||||
*/
|
||||
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#include <stdint.h>
|
||||
#include <thrift/protocol/TDenseProtocol.h>
|
||||
#include <thrift/TReflectionLocal.h>
|
||||
|
||||
// Leaving this on for now. Disabling it will turn off asserts, which should
|
||||
// give a performance boost. When we have *really* thorough test cases,
|
||||
// we should drop this.
|
||||
#define DEBUG_TDENSEPROTOCOL
|
||||
|
||||
// NOTE: Assertions should *only* be used to detect bugs in code,
|
||||
// either in TDenseProtocol itself, or in code using it.
|
||||
// (For example, using the wrong TypeSpec.)
|
||||
// Invalid data should NEVER cause an assertion failure,
|
||||
// no matter how grossly corrupted, nor how ingeniously crafted.
|
||||
#ifdef DEBUG_TDENSEPROTOCOL
|
||||
#undef NDEBUG
|
||||
#else
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#include <cassert>
|
||||
|
||||
using std::string;
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UNLIKELY(val) (__builtin_expect((val), 0))
|
||||
#else
|
||||
#define UNLIKELY(val) (val)
|
||||
#endif
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
|
||||
const int TDenseProtocol::FP_PREFIX_LEN =
|
||||
apache::thrift::reflection::local::FP_PREFIX_LEN;
|
||||
|
||||
// Top TypeSpec. TypeSpec of the structure being encoded.
|
||||
#define TTS (ts_stack_.back()) // type = TypeSpec*
|
||||
// InDeX. Index into TTS of the current/next field to encode.
|
||||
#define IDX (idx_stack_.back()) // type = int
|
||||
// Field TypeSpec. TypeSpec of the current/next field to encode.
|
||||
#define FTS (TTS->tstruct.specs[IDX]) // type = TypeSpec*
|
||||
// Field MeTa. Metadata of the current/next field to encode.
|
||||
#define FMT (TTS->tstruct.metas[IDX]) // type = FieldMeta
|
||||
// SubType 1/2. TypeSpec of the first/second subtype of this container.
|
||||
#define ST1 (TTS->tcontainer.subtype1)
|
||||
#define ST2 (TTS->tcontainer.subtype2)
|
||||
|
||||
|
||||
/**
|
||||
* Checks that @c ttype is indeed the ttype that we should be writing,
|
||||
* according to our typespec. Aborts if the test fails and debugging in on.
|
||||
*/
|
||||
inline void TDenseProtocol::checkTType(const TType ttype) {
|
||||
assert(!ts_stack_.empty());
|
||||
assert(TTS->ttype == ttype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the TypeSpec stack is correct for the next object.
|
||||
* See top-of-file comments.
|
||||
*/
|
||||
inline void TDenseProtocol::stateTransition() {
|
||||
TypeSpec* old_tts = ts_stack_.back();
|
||||
ts_stack_.pop_back();
|
||||
|
||||
// If this is the end of the top-level write, we should have just popped
|
||||
// the TypeSpec passed to the constructor.
|
||||
if (ts_stack_.empty()) {
|
||||
assert(old_tts = type_spec_);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TTS->ttype) {
|
||||
|
||||
case T_STRUCT:
|
||||
assert(old_tts == FTS);
|
||||
break;
|
||||
|
||||
case T_LIST:
|
||||
case T_SET:
|
||||
assert(old_tts == ST1);
|
||||
ts_stack_.push_back(old_tts);
|
||||
break;
|
||||
|
||||
case T_MAP:
|
||||
assert(old_tts == (mkv_stack_.back() ? ST1 : ST2));
|
||||
mkv_stack_.back() = !mkv_stack_.back();
|
||||
ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(!"Invalid TType in stateTransition.");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Variable-length quantity functions.
|
||||
*/
|
||||
|
||||
inline uint32_t TDenseProtocol::vlqRead(uint64_t& vlq) {
|
||||
uint32_t used = 0;
|
||||
uint64_t val = 0;
|
||||
uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
|
||||
uint32_t buf_size = sizeof(buf);
|
||||
const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
|
||||
|
||||
// Fast path. TODO(dreiss): Make it faster.
|
||||
if (borrowed != NULL) {
|
||||
while (true) {
|
||||
uint8_t byte = borrowed[used];
|
||||
used++;
|
||||
val = (val << 7) | (byte & 0x7f);
|
||||
if (!(byte & 0x80)) {
|
||||
vlq = val;
|
||||
trans_->consume(used);
|
||||
return used;
|
||||
}
|
||||
// Have to check for invalid data so we don't crash.
|
||||
if (UNLIKELY(used == sizeof(buf))) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Slow path.
|
||||
else {
|
||||
while (true) {
|
||||
uint8_t byte;
|
||||
used += trans_->readAll(&byte, 1);
|
||||
val = (val << 7) | (byte & 0x7f);
|
||||
if (!(byte & 0x80)) {
|
||||
vlq = val;
|
||||
return used;
|
||||
}
|
||||
// Might as well check for invalid data on the slow path too.
|
||||
if (UNLIKELY(used >= sizeof(buf))) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t TDenseProtocol::vlqWrite(uint64_t vlq) {
|
||||
uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
|
||||
int32_t pos = sizeof(buf) - 1;
|
||||
|
||||
// Write the thing from back to front.
|
||||
buf[pos] = vlq & 0x7f;
|
||||
vlq >>= 7;
|
||||
pos--;
|
||||
|
||||
while (vlq > 0) {
|
||||
assert(pos >= 0);
|
||||
buf[pos] = static_cast<uint8_t>(vlq | 0x80);
|
||||
vlq >>= 7;
|
||||
pos--;
|
||||
}
|
||||
|
||||
// Back up one step before writing.
|
||||
pos++;
|
||||
|
||||
trans_->write(buf+pos, sizeof(buf) - pos);
|
||||
return sizeof(buf) - pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Writing functions.
|
||||
*/
|
||||
|
||||
uint32_t TDenseProtocol::writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) {
|
||||
throw TException("TDenseProtocol doesn't work with messages (yet).");
|
||||
|
||||
int32_t version = (VERSION_2) | ((int32_t)messageType);
|
||||
uint32_t wsize = 0;
|
||||
wsize += subWriteI32(version);
|
||||
wsize += subWriteString(name);
|
||||
wsize += subWriteI32(seqid);
|
||||
return wsize;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeMessageEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeStructBegin(const char* name) {
|
||||
(void) name;
|
||||
uint32_t xfer = 0;
|
||||
|
||||
// The TypeSpec stack should be empty if this is the top-level read/write.
|
||||
// If it is, we push the TypeSpec passed to the constructor.
|
||||
if (ts_stack_.empty()) {
|
||||
assert(standalone_);
|
||||
|
||||
if (type_spec_ == NULL) {
|
||||
resetState();
|
||||
throw TException("TDenseProtocol: No type specified.");
|
||||
} else {
|
||||
assert(type_spec_->ttype == T_STRUCT);
|
||||
ts_stack_.push_back(type_spec_);
|
||||
// Write out a prefix of the structure fingerprint.
|
||||
trans_->write(type_spec_->fp_prefix, FP_PREFIX_LEN);
|
||||
xfer += FP_PREFIX_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
// We need a new field index for this structure.
|
||||
idx_stack_.push_back(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeStructEnd() {
|
||||
idx_stack_.pop_back();
|
||||
stateTransition();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) {
|
||||
(void) name;
|
||||
uint32_t xfer = 0;
|
||||
|
||||
// Skip over optional fields.
|
||||
while (FMT.tag != fieldId) {
|
||||
// TODO(dreiss): Old meta here.
|
||||
assert(FTS->ttype != T_STOP);
|
||||
assert(FMT.is_optional);
|
||||
// Write a zero byte so the reader can skip it.
|
||||
xfer += subWriteBool(false);
|
||||
// And advance to the next field.
|
||||
IDX++;
|
||||
}
|
||||
|
||||
// TODO(dreiss): give a better exception.
|
||||
assert(FTS->ttype == fieldType);
|
||||
|
||||
if (FMT.is_optional) {
|
||||
subWriteBool(true);
|
||||
xfer += 1;
|
||||
}
|
||||
|
||||
// writeFieldStop shares all lot of logic up to this point.
|
||||
// Instead of replicating it all, we just call this method from that one
|
||||
// and use a gross special case here.
|
||||
if (UNLIKELY(FTS->ttype != T_STOP)) {
|
||||
// For normal fields, push the TypeSpec that we're about to use.
|
||||
ts_stack_.push_back(FTS);
|
||||
}
|
||||
return xfer;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeFieldEnd() {
|
||||
// Just move on to the next field.
|
||||
IDX++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeFieldStop() {
|
||||
return TDenseProtocol::writeFieldBegin("", T_STOP, 0);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) {
|
||||
checkTType(T_MAP);
|
||||
|
||||
assert(keyType == ST1->ttype);
|
||||
assert(valType == ST2->ttype);
|
||||
|
||||
ts_stack_.push_back(ST1);
|
||||
mkv_stack_.push_back(true);
|
||||
|
||||
return subWriteI32((int32_t)size);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeMapEnd() {
|
||||
// Pop off the value type, as well as our entry in the map key/value stack.
|
||||
// stateTransition takes care of popping off our TypeSpec.
|
||||
ts_stack_.pop_back();
|
||||
mkv_stack_.pop_back();
|
||||
stateTransition();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeListBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
checkTType(T_LIST);
|
||||
|
||||
assert(elemType == ST1->ttype);
|
||||
ts_stack_.push_back(ST1);
|
||||
return subWriteI32((int32_t)size);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeListEnd() {
|
||||
// Pop off the element type. stateTransition takes care of popping off ours.
|
||||
ts_stack_.pop_back();
|
||||
stateTransition();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
checkTType(T_SET);
|
||||
|
||||
assert(elemType == ST1->ttype);
|
||||
ts_stack_.push_back(ST1);
|
||||
return subWriteI32((int32_t)size);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeSetEnd() {
|
||||
// Pop off the element type. stateTransition takes care of popping off ours.
|
||||
ts_stack_.pop_back();
|
||||
stateTransition();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeBool(const bool value) {
|
||||
checkTType(T_BOOL);
|
||||
stateTransition();
|
||||
return TBinaryProtocol::writeBool(value);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeByte(const int8_t byte) {
|
||||
checkTType(T_BYTE);
|
||||
stateTransition();
|
||||
return TBinaryProtocol::writeByte(byte);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeI16(const int16_t i16) {
|
||||
checkTType(T_I16);
|
||||
stateTransition();
|
||||
return vlqWrite(i16);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeI32(const int32_t i32) {
|
||||
checkTType(T_I32);
|
||||
stateTransition();
|
||||
return vlqWrite(i32);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeI64(const int64_t i64) {
|
||||
checkTType(T_I64);
|
||||
stateTransition();
|
||||
return vlqWrite(i64);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeDouble(const double dub) {
|
||||
checkTType(T_DOUBLE);
|
||||
stateTransition();
|
||||
return TBinaryProtocol::writeDouble(dub);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeString(const std::string& str) {
|
||||
checkTType(T_STRING);
|
||||
stateTransition();
|
||||
return subWriteString(str);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::writeBinary(const std::string& str) {
|
||||
return TDenseProtocol::writeString(str);
|
||||
}
|
||||
|
||||
inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
|
||||
return vlqWrite(i32);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::subWriteString(const std::string& str) {
|
||||
if(str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
uint32_t size = static_cast<uint32_t>(str.size());
|
||||
uint32_t xfer = subWriteI32((int32_t)size);
|
||||
if (size > 0) {
|
||||
trans_->write((uint8_t*)str.data(), size);
|
||||
}
|
||||
return xfer + size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Reading functions
|
||||
*
|
||||
* These have a lot of the same logic as the writing functions, so if
|
||||
* something is confusing, look for comments in the corresponding writer.
|
||||
*/
|
||||
|
||||
uint32_t TDenseProtocol::readMessageBegin(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) {
|
||||
throw TException("TDenseProtocol doesn't work with messages (yet).");
|
||||
|
||||
uint32_t xfer = 0;
|
||||
int32_t sz;
|
||||
xfer += subReadI32(sz);
|
||||
|
||||
if (sz < 0) {
|
||||
// Check for correct version number
|
||||
int32_t version = sz & VERSION_MASK;
|
||||
if (version != VERSION_2) {
|
||||
throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
|
||||
}
|
||||
messageType = (TMessageType)(sz & 0x000000ff);
|
||||
xfer += subReadString(name);
|
||||
xfer += subReadI32(seqid);
|
||||
} else {
|
||||
throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
|
||||
}
|
||||
return xfer;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readMessageEnd() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readStructBegin(string& name) {
|
||||
(void) name;
|
||||
uint32_t xfer = 0;
|
||||
|
||||
if (ts_stack_.empty()) {
|
||||
assert(standalone_);
|
||||
|
||||
if (type_spec_ == NULL) {
|
||||
resetState();
|
||||
throw TException("TDenseProtocol: No type specified.");
|
||||
} else {
|
||||
assert(type_spec_->ttype == T_STRUCT);
|
||||
ts_stack_.push_back(type_spec_);
|
||||
|
||||
// Check the fingerprint prefix.
|
||||
uint8_t buf[FP_PREFIX_LEN];
|
||||
xfer += trans_->read(buf, FP_PREFIX_LEN);
|
||||
if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA,
|
||||
"Fingerprint in data does not match type_spec.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We need a new field index for this structure.
|
||||
idx_stack_.push_back(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readStructEnd() {
|
||||
idx_stack_.pop_back();
|
||||
stateTransition();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readFieldBegin(string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) {
|
||||
(void) name;
|
||||
uint32_t xfer = 0;
|
||||
|
||||
// For optional fields, check to see if they are there.
|
||||
while (FMT.is_optional) {
|
||||
bool is_present;
|
||||
xfer += subReadBool(is_present);
|
||||
if (is_present) {
|
||||
break;
|
||||
}
|
||||
IDX++;
|
||||
}
|
||||
|
||||
// Once we hit a mandatory field, or an optional field that is present,
|
||||
// we know that FMT and FTS point to the appropriate field.
|
||||
|
||||
fieldId = FMT.tag;
|
||||
fieldType = FTS->ttype;
|
||||
|
||||
// Normally, we push the TypeSpec that we are about to read,
|
||||
// but no reading is done for T_STOP.
|
||||
if (FTS->ttype != T_STOP) {
|
||||
ts_stack_.push_back(FTS);
|
||||
}
|
||||
return xfer;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readFieldEnd() {
|
||||
IDX++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readMapBegin(TType& keyType,
|
||||
TType& valType,
|
||||
uint32_t& size) {
|
||||
checkTType(T_MAP);
|
||||
|
||||
uint32_t xfer = 0;
|
||||
int32_t sizei;
|
||||
xfer += subReadI32(sizei);
|
||||
if (sizei < 0) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
} else if (container_limit_ && sizei > container_limit_) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
size = (uint32_t)sizei;
|
||||
|
||||
keyType = ST1->ttype;
|
||||
valType = ST2->ttype;
|
||||
|
||||
ts_stack_.push_back(ST1);
|
||||
mkv_stack_.push_back(true);
|
||||
|
||||
return xfer;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readMapEnd() {
|
||||
ts_stack_.pop_back();
|
||||
mkv_stack_.pop_back();
|
||||
stateTransition();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readListBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
checkTType(T_LIST);
|
||||
|
||||
uint32_t xfer = 0;
|
||||
int32_t sizei;
|
||||
xfer += subReadI32(sizei);
|
||||
if (sizei < 0) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
} else if (container_limit_ && sizei > container_limit_) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
size = (uint32_t)sizei;
|
||||
|
||||
elemType = ST1->ttype;
|
||||
|
||||
ts_stack_.push_back(ST1);
|
||||
|
||||
return xfer;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readListEnd() {
|
||||
ts_stack_.pop_back();
|
||||
stateTransition();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readSetBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
checkTType(T_SET);
|
||||
|
||||
uint32_t xfer = 0;
|
||||
int32_t sizei;
|
||||
xfer += subReadI32(sizei);
|
||||
if (sizei < 0) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
|
||||
} else if (container_limit_ && sizei > container_limit_) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::SIZE_LIMIT);
|
||||
}
|
||||
size = (uint32_t)sizei;
|
||||
|
||||
elemType = ST1->ttype;
|
||||
|
||||
ts_stack_.push_back(ST1);
|
||||
|
||||
return xfer;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readSetEnd() {
|
||||
ts_stack_.pop_back();
|
||||
stateTransition();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readBool(bool& value) {
|
||||
checkTType(T_BOOL);
|
||||
stateTransition();
|
||||
return TBinaryProtocol::readBool(value);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readByte(int8_t& byte) {
|
||||
checkTType(T_BYTE);
|
||||
stateTransition();
|
||||
return TBinaryProtocol::readByte(byte);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readI16(int16_t& i16) {
|
||||
checkTType(T_I16);
|
||||
stateTransition();
|
||||
uint64_t u64;
|
||||
uint32_t rv = vlqRead(u64);
|
||||
int64_t val = (int64_t)u64;
|
||||
if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA,
|
||||
"i16 out of range.");
|
||||
}
|
||||
i16 = (int16_t)val;
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readI32(int32_t& i32) {
|
||||
checkTType(T_I32);
|
||||
stateTransition();
|
||||
uint64_t u64;
|
||||
uint32_t rv = vlqRead(u64);
|
||||
int64_t val = (int64_t)u64;
|
||||
if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA,
|
||||
"i32 out of range.");
|
||||
}
|
||||
i32 = (int32_t)val;
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readI64(int64_t& i64) {
|
||||
checkTType(T_I64);
|
||||
stateTransition();
|
||||
uint64_t u64;
|
||||
uint32_t rv = vlqRead(u64);
|
||||
int64_t val = (int64_t)u64;
|
||||
if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA,
|
||||
"i64 out of range.");
|
||||
}
|
||||
i64 = (int64_t)val;
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readDouble(double& dub) {
|
||||
checkTType(T_DOUBLE);
|
||||
stateTransition();
|
||||
return TBinaryProtocol::readDouble(dub);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readString(std::string& str) {
|
||||
checkTType(T_STRING);
|
||||
stateTransition();
|
||||
return subReadString(str);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::readBinary(std::string& str) {
|
||||
return TDenseProtocol::readString(str);
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
|
||||
uint64_t u64;
|
||||
uint32_t rv = vlqRead(u64);
|
||||
int64_t val = (int64_t)u64;
|
||||
if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
|
||||
resetState();
|
||||
throw TProtocolException(TProtocolException::INVALID_DATA,
|
||||
"i32 out of range.");
|
||||
}
|
||||
i32 = (int32_t)val;
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t TDenseProtocol::subReadString(std::string& str) {
|
||||
uint32_t xfer;
|
||||
int32_t size;
|
||||
xfer = subReadI32(size);
|
||||
return xfer + readStringBody(str, size);
|
||||
}
|
||||
|
||||
}}} // apache::thrift::protocol
|
|
@ -56,11 +56,12 @@ namespace apache { namespace thrift { namespace protocol {
|
|||
* methods within our versions.
|
||||
*
|
||||
*/
|
||||
class TDenseProtocol : public TBinaryProtocol {
|
||||
class TDenseProtocol
|
||||
: public TVirtualProtocol<TDenseProtocol, TBinaryProtocol> {
|
||||
protected:
|
||||
static const int32_t VERSION_MASK = 0xffff0000;
|
||||
static const int32_t VERSION_MASK = ((int32_t)0xffff0000);
|
||||
// VERSION_1 (0x80010000) is taken by TBinaryProtocol.
|
||||
static const int32_t VERSION_2 = 0x80020000;
|
||||
static const int32_t VERSION_2 = ((int32_t)0x80020000);
|
||||
|
||||
public:
|
||||
typedef apache::thrift::reflection::local::TypeSpec TypeSpec;
|
||||
|
@ -72,7 +73,7 @@ class TDenseProtocol : public TBinaryProtocol {
|
|||
*/
|
||||
TDenseProtocol(boost::shared_ptr<TTransport> trans,
|
||||
TypeSpec* type_spec = NULL) :
|
||||
TBinaryProtocol(trans),
|
||||
TVirtualProtocol<TDenseProtocol, TBinaryProtocol>(trans),
|
||||
type_spec_(type_spec),
|
||||
standalone_(true)
|
||||
{}
|
||||
|
@ -89,56 +90,54 @@ class TDenseProtocol : public TBinaryProtocol {
|
|||
* Writing functions.
|
||||
*/
|
||||
|
||||
virtual uint32_t writeMessageBegin(const std::string& name,
|
||||
uint32_t writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid);
|
||||
|
||||
virtual uint32_t writeMessageEnd();
|
||||
uint32_t writeMessageEnd();
|
||||
|
||||
|
||||
virtual uint32_t writeStructBegin(const char* name);
|
||||
uint32_t writeStructBegin(const char* name);
|
||||
|
||||
virtual uint32_t writeStructEnd();
|
||||
uint32_t writeStructEnd();
|
||||
|
||||
virtual uint32_t writeFieldBegin(const char* name,
|
||||
uint32_t writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId);
|
||||
|
||||
virtual uint32_t writeFieldEnd();
|
||||
uint32_t writeFieldEnd();
|
||||
|
||||
virtual uint32_t writeFieldStop();
|
||||
uint32_t writeFieldStop();
|
||||
|
||||
virtual uint32_t writeMapBegin(const TType keyType,
|
||||
uint32_t writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size);
|
||||
|
||||
virtual uint32_t writeMapEnd();
|
||||
uint32_t writeMapEnd();
|
||||
|
||||
virtual uint32_t writeListBegin(const TType elemType,
|
||||
const uint32_t size);
|
||||
uint32_t writeListBegin(const TType elemType, const uint32_t size);
|
||||
|
||||
virtual uint32_t writeListEnd();
|
||||
uint32_t writeListEnd();
|
||||
|
||||
virtual uint32_t writeSetBegin(const TType elemType,
|
||||
const uint32_t size);
|
||||
uint32_t writeSetBegin(const TType elemType, const uint32_t size);
|
||||
|
||||
virtual uint32_t writeSetEnd();
|
||||
uint32_t writeSetEnd();
|
||||
|
||||
virtual uint32_t writeBool(const bool value);
|
||||
uint32_t writeBool(const bool value);
|
||||
|
||||
virtual uint32_t writeByte(const int8_t byte);
|
||||
uint32_t writeByte(const int8_t byte);
|
||||
|
||||
virtual uint32_t writeI16(const int16_t i16);
|
||||
uint32_t writeI16(const int16_t i16);
|
||||
|
||||
virtual uint32_t writeI32(const int32_t i32);
|
||||
uint32_t writeI32(const int32_t i32);
|
||||
|
||||
virtual uint32_t writeI64(const int64_t i64);
|
||||
uint32_t writeI64(const int64_t i64);
|
||||
|
||||
virtual uint32_t writeDouble(const double dub);
|
||||
uint32_t writeDouble(const double dub);
|
||||
|
||||
virtual uint32_t writeString(const std::string& str);
|
||||
uint32_t writeString(const std::string& str);
|
||||
|
||||
virtual uint32_t writeBinary(const std::string& str);
|
||||
uint32_t writeBinary(const std::string& str);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -190,6 +189,8 @@ class TDenseProtocol : public TBinaryProtocol {
|
|||
uint32_t readSetEnd();
|
||||
|
||||
uint32_t readBool(bool& value);
|
||||
// Provide the default readBool() implementation for std::vector<bool>
|
||||
using TVirtualProtocol<TDenseProtocol, TBinaryProtocol>::readBool;
|
||||
|
||||
uint32_t readByte(int8_t& byte);
|
||||
|
||||
|
|
1023
nativeLib/org.apache.thrift/include/protocol/TJSONProtocol.cpp
Normal file
1023
nativeLib/org.apache.thrift/include/protocol/TJSONProtocol.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,7 @@
|
|||
#ifndef _THRIFT_PROTOCOL_TJSONPROTOCOL_H_
|
||||
#define _THRIFT_PROTOCOL_TJSONPROTOCOL_H_ 1
|
||||
|
||||
#include "TProtocol.h"
|
||||
#include "TVirtualProtocol.h"
|
||||
|
||||
#include <stack>
|
||||
|
||||
|
@ -86,13 +86,8 @@ class TJSONContext;
|
|||
* may try to provide a C component for this, so that other languages could
|
||||
* bind to the same underlying implementation for maximum consistency.
|
||||
*
|
||||
* Note further that JavaScript itself is not capable of representing
|
||||
* floating point infinities -- presumably when we have a JavaScript Thrift
|
||||
* client, this would mean that infinities get converted to not-a-number in
|
||||
* transmission. I don't know of any work-around for this issue.
|
||||
*
|
||||
*/
|
||||
class TJSONProtocol : public TProtocol {
|
||||
class TJSONProtocol : public TVirtualProtocol<TJSONProtocol> {
|
||||
public:
|
||||
|
||||
TJSONProtocol(boost::shared_ptr<TTransport> ptrans);
|
||||
|
@ -243,6 +238,9 @@ class TJSONProtocol : public TProtocol {
|
|||
|
||||
uint32_t readBool(bool& value);
|
||||
|
||||
// Provide the default readBool() implementation for std::vector<bool>
|
||||
using TVirtualProtocol<TJSONProtocol>::readBool;
|
||||
|
||||
uint32_t readByte(int8_t& byte);
|
||||
|
||||
uint32_t readI16(int16_t& i16);
|
||||
|
@ -291,6 +289,7 @@ class TJSONProtocol : public TProtocol {
|
|||
};
|
||||
|
||||
private:
|
||||
TTransport* trans_;
|
||||
|
||||
std::stack<boost::shared_ptr<TJSONContext> > contexts_;
|
||||
boost::shared_ptr<TJSONContext> context_;
|
||||
|
@ -315,7 +314,7 @@ class TJSONProtocolFactory : public TProtocolFactory {
|
|||
|
||||
|
||||
// TODO(dreiss): Move part of ThriftJSONString into a .cpp file and remove this.
|
||||
#include <transport/TBufferTransports.h>
|
||||
#include <thrift/transport/TBufferTransports.h>
|
||||
|
||||
namespace apache { namespace thrift {
|
||||
|
||||
|
|
|
@ -1,304 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_PROTOCOL_TONEWAYPROTOCOL_H_
|
||||
#define _THRIFT_PROTOCOL_TONEWAYPROTOCOL_H_ 1
|
||||
|
||||
#include "TProtocol.h"
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
|
||||
/**
|
||||
* Abstract class for implementing a protocol that can only be written,
|
||||
* not read.
|
||||
*
|
||||
*/
|
||||
class TWriteOnlyProtocol : public TProtocol {
|
||||
public:
|
||||
/**
|
||||
* @param subclass_name The name of the concrete subclass.
|
||||
*/
|
||||
TWriteOnlyProtocol(boost::shared_ptr<TTransport> trans,
|
||||
const std::string& subclass_name)
|
||||
: TProtocol(trans)
|
||||
, subclass_(subclass_name)
|
||||
{}
|
||||
|
||||
// All writing functions remain abstract.
|
||||
|
||||
/**
|
||||
* Reading functions all throw an exception.
|
||||
*/
|
||||
|
||||
uint32_t readMessageBegin(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readMessageEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readStructBegin(std::string& name) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readStructEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readFieldBegin(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readFieldEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readMapBegin(TType& keyType,
|
||||
TType& valType,
|
||||
uint32_t& size) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readMapEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readListBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readListEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readSetBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readSetEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readBool(bool& value) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readByte(int8_t& byte) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readI16(int16_t& i16) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readI32(int32_t& i32) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readI64(int64_t& i64) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readDouble(double& dub) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readString(std::string& str) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readBinary(std::string& str) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support reading (yet).");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string subclass_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for implementing a protocol that can only be read,
|
||||
* not written.
|
||||
*
|
||||
*/
|
||||
class TReadOnlyProtocol : public TProtocol {
|
||||
public:
|
||||
/**
|
||||
* @param subclass_name The name of the concrete subclass.
|
||||
*/
|
||||
TReadOnlyProtocol(boost::shared_ptr<TTransport> trans,
|
||||
const std::string& subclass_name)
|
||||
: TProtocol(trans)
|
||||
, subclass_(subclass_name)
|
||||
{}
|
||||
|
||||
// All reading functions remain abstract.
|
||||
|
||||
/**
|
||||
* Writing functions all throw an exception.
|
||||
*/
|
||||
|
||||
uint32_t writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeMessageEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
|
||||
uint32_t writeStructBegin(const char* name) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeStructEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeFieldEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeFieldStop() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeMapEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeListBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeListEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeSetBegin(const TType elemType,
|
||||
const uint32_t size) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeSetEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeBool(const bool value) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeByte(const int8_t byte) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeI16(const int16_t i16) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeI32(const int32_t i32) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeI64(const int64_t i64) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeDouble(const double dub) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeString(const std::string& str) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeBinary(const std::string& str) {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
subclass_ + " does not support writing (yet).");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string subclass_;
|
||||
};
|
||||
|
||||
}}} // apache::thrift::protocol
|
||||
|
||||
#endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_
|
|
@ -20,16 +20,19 @@
|
|||
#ifndef _THRIFT_PROTOCOL_TPROTOCOL_H_
|
||||
#define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1
|
||||
|
||||
#include <transport/TTransport.h>
|
||||
#include <protocol/TProtocolException.h>
|
||||
#include <thrift/transport/TTransport.h>
|
||||
#include <thrift/protocol/TProtocolException.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// Use this to get around strict aliasing rules.
|
||||
|
@ -76,24 +79,30 @@ namespace apache { namespace thrift { namespace protocol {
|
|||
|
||||
using apache::thrift::transport::TTransport;
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H_
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifndef __BYTE_ORDER
|
||||
#ifndef __THRIFT_BYTE_ORDER
|
||||
# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
|
||||
# define __BYTE_ORDER BYTE_ORDER
|
||||
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __BIG_ENDIAN BIG_ENDIAN
|
||||
# define __THRIFT_BYTE_ORDER BYTE_ORDER
|
||||
# define __THRIFT_LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __THRIFT_BIG_ENDIAN BIG_ENDIAN
|
||||
# else
|
||||
# include <boost/config.hpp>
|
||||
# define __BYTE_ORDER BOOST_BYTE_ORDER
|
||||
# define __LITTLE_ENDIAN BOOST_LITTLE_ENDIAN
|
||||
# define __BIG_ENDIAN BOOST_BIG_ENDIAN
|
||||
# include <boost/detail/endian.hpp>
|
||||
# define __THRIFT_BYTE_ORDER BOOST_BYTE_ORDER
|
||||
# ifdef BOOST_LITTLE_ENDIAN
|
||||
# define __THRIFT_LITTLE_ENDIAN __THRIFT_BYTE_ORDER
|
||||
# define __THRIFT_BIG_ENDIAN 0
|
||||
# else
|
||||
# define __THRIFT_LITTLE_ENDIAN 0
|
||||
# define __THRIFT_BIG_ENDIAN __THRIFT_BYTE_ORDER
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
|
||||
# define ntohll(n) (n)
|
||||
# define htonll(n) (n)
|
||||
# if defined(__GNUC__) && defined(__GLIBC__)
|
||||
|
@ -113,18 +122,21 @@ using apache::thrift::transport::TTransport;
|
|||
# define htolell(n) bswap_64(n)
|
||||
# define letohll(n) bswap_64(n)
|
||||
# endif /* GNUC & GLIBC */
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
|
||||
# define htolell(n) (n)
|
||||
# define letohll(n) (n)
|
||||
# if defined(__GNUC__) && defined(__GLIBC__)
|
||||
# include <byteswap.h>
|
||||
# define ntohll(n) bswap_64(n)
|
||||
# define htonll(n) bswap_64(n)
|
||||
# else /* GNUC & GLIBC */
|
||||
# define ntohll(n) ( (((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32) )
|
||||
# define htonll(n) ( (((unsigned long long)htonl(n)) << 32) + htonl(n >> 32) )
|
||||
# endif /* GNUC & GLIBC */
|
||||
#else /* __BYTE_ORDER */
|
||||
# elif defined(_MSC_VER) /* Microsoft Visual C++ */
|
||||
# define ntohll(n) ( _byteswap_uint64((uint64_t)n) )
|
||||
# define htonll(n) ( _byteswap_uint64((uint64_t)n) )
|
||||
# else /* Not GNUC/GLIBC or MSVC */
|
||||
# define ntohll(n) ( (((uint64_t)ntohl(n)) << 32) + ntohl(n >> 32) )
|
||||
# define htonll(n) ( (((uint64_t)htonl(n)) << 32) + htonl(n >> 32) )
|
||||
# endif /* GNUC/GLIBC or MSVC or something else */
|
||||
#else /* __THRIFT_BYTE_ORDER */
|
||||
# error "Can't define htonll or ntohll!"
|
||||
#endif
|
||||
|
||||
|
@ -165,6 +177,112 @@ enum TMessageType {
|
|||
T_ONEWAY = 4
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper template for implementing TProtocol::skip().
|
||||
*
|
||||
* Templatized to avoid having to make virtual function calls.
|
||||
*/
|
||||
template <class Protocol_>
|
||||
uint32_t skip(Protocol_& prot, TType type) {
|
||||
switch (type) {
|
||||
case T_BOOL:
|
||||
{
|
||||
bool boolv;
|
||||
return prot.readBool(boolv);
|
||||
}
|
||||
case T_BYTE:
|
||||
{
|
||||
int8_t bytev;
|
||||
return prot.readByte(bytev);
|
||||
}
|
||||
case T_I16:
|
||||
{
|
||||
int16_t i16;
|
||||
return prot.readI16(i16);
|
||||
}
|
||||
case T_I32:
|
||||
{
|
||||
int32_t i32;
|
||||
return prot.readI32(i32);
|
||||
}
|
||||
case T_I64:
|
||||
{
|
||||
int64_t i64;
|
||||
return prot.readI64(i64);
|
||||
}
|
||||
case T_DOUBLE:
|
||||
{
|
||||
double dub;
|
||||
return prot.readDouble(dub);
|
||||
}
|
||||
case T_STRING:
|
||||
{
|
||||
std::string str;
|
||||
return prot.readBinary(str);
|
||||
}
|
||||
case T_STRUCT:
|
||||
{
|
||||
uint32_t result = 0;
|
||||
std::string name;
|
||||
int16_t fid;
|
||||
TType ftype;
|
||||
result += prot.readStructBegin(name);
|
||||
while (true) {
|
||||
result += prot.readFieldBegin(name, ftype, fid);
|
||||
if (ftype == T_STOP) {
|
||||
break;
|
||||
}
|
||||
result += skip(prot, ftype);
|
||||
result += prot.readFieldEnd();
|
||||
}
|
||||
result += prot.readStructEnd();
|
||||
return result;
|
||||
}
|
||||
case T_MAP:
|
||||
{
|
||||
uint32_t result = 0;
|
||||
TType keyType;
|
||||
TType valType;
|
||||
uint32_t i, size;
|
||||
result += prot.readMapBegin(keyType, valType, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
result += skip(prot, keyType);
|
||||
result += skip(prot, valType);
|
||||
}
|
||||
result += prot.readMapEnd();
|
||||
return result;
|
||||
}
|
||||
case T_SET:
|
||||
{
|
||||
uint32_t result = 0;
|
||||
TType elemType;
|
||||
uint32_t i, size;
|
||||
result += prot.readSetBegin(elemType, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
result += skip(prot, elemType);
|
||||
}
|
||||
result += prot.readSetEnd();
|
||||
return result;
|
||||
}
|
||||
case T_LIST:
|
||||
{
|
||||
uint32_t result = 0;
|
||||
TType elemType;
|
||||
uint32_t i, size;
|
||||
result += prot.readListBegin(elemType, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
result += skip(prot, elemType);
|
||||
}
|
||||
result += prot.readListEnd();
|
||||
return result;
|
||||
}
|
||||
case T_STOP: case T_VOID: case T_U64: case T_UTF8: case T_UTF16:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract class for a thrift protocol driver. These are all the methods that
|
||||
* a protocol must implement. Essentially, there must be some way of reading
|
||||
|
@ -187,215 +305,346 @@ class TProtocol {
|
|||
* Writing functions.
|
||||
*/
|
||||
|
||||
virtual uint32_t writeMessageBegin(const std::string& name,
|
||||
virtual uint32_t writeMessageBegin_virt(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) = 0;
|
||||
|
||||
virtual uint32_t writeMessageEnd() = 0;
|
||||
virtual uint32_t writeMessageEnd_virt() = 0;
|
||||
|
||||
|
||||
virtual uint32_t writeStructBegin(const char* name) = 0;
|
||||
virtual uint32_t writeStructBegin_virt(const char* name) = 0;
|
||||
|
||||
virtual uint32_t writeStructEnd() = 0;
|
||||
virtual uint32_t writeStructEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t writeFieldBegin(const char* name,
|
||||
virtual uint32_t writeFieldBegin_virt(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) = 0;
|
||||
|
||||
virtual uint32_t writeFieldEnd() = 0;
|
||||
virtual uint32_t writeFieldEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t writeFieldStop() = 0;
|
||||
virtual uint32_t writeFieldStop_virt() = 0;
|
||||
|
||||
virtual uint32_t writeMapBegin(const TType keyType,
|
||||
virtual uint32_t writeMapBegin_virt(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) = 0;
|
||||
|
||||
virtual uint32_t writeMapEnd() = 0;
|
||||
virtual uint32_t writeMapEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t writeListBegin(const TType elemType,
|
||||
virtual uint32_t writeListBegin_virt(const TType elemType,
|
||||
const uint32_t size) = 0;
|
||||
|
||||
virtual uint32_t writeListEnd() = 0;
|
||||
virtual uint32_t writeListEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t writeSetBegin(const TType elemType,
|
||||
virtual uint32_t writeSetBegin_virt(const TType elemType,
|
||||
const uint32_t size) = 0;
|
||||
|
||||
virtual uint32_t writeSetEnd() = 0;
|
||||
virtual uint32_t writeSetEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t writeBool(const bool value) = 0;
|
||||
virtual uint32_t writeBool_virt(const bool value) = 0;
|
||||
|
||||
virtual uint32_t writeByte(const int8_t byte) = 0;
|
||||
virtual uint32_t writeByte_virt(const int8_t byte) = 0;
|
||||
|
||||
virtual uint32_t writeI16(const int16_t i16) = 0;
|
||||
virtual uint32_t writeI16_virt(const int16_t i16) = 0;
|
||||
|
||||
virtual uint32_t writeI32(const int32_t i32) = 0;
|
||||
virtual uint32_t writeI32_virt(const int32_t i32) = 0;
|
||||
|
||||
virtual uint32_t writeI64(const int64_t i64) = 0;
|
||||
virtual uint32_t writeI64_virt(const int64_t i64) = 0;
|
||||
|
||||
virtual uint32_t writeDouble(const double dub) = 0;
|
||||
virtual uint32_t writeDouble_virt(const double dub) = 0;
|
||||
|
||||
virtual uint32_t writeString(const std::string& str) = 0;
|
||||
virtual uint32_t writeString_virt(const std::string& str) = 0;
|
||||
|
||||
virtual uint32_t writeBinary(const std::string& str) = 0;
|
||||
virtual uint32_t writeBinary_virt(const std::string& str) = 0;
|
||||
|
||||
uint32_t writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeMessageBegin_virt(name, messageType, seqid);
|
||||
}
|
||||
|
||||
uint32_t writeMessageEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeMessageEnd_virt();
|
||||
}
|
||||
|
||||
|
||||
uint32_t writeStructBegin(const char* name) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeStructBegin_virt(name);
|
||||
}
|
||||
|
||||
uint32_t writeStructEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeStructEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeFieldBegin_virt(name, fieldType, fieldId);
|
||||
}
|
||||
|
||||
uint32_t writeFieldEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeFieldEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t writeFieldStop() {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeFieldStop_virt();
|
||||
}
|
||||
|
||||
uint32_t writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeMapBegin_virt(keyType, valType, size);
|
||||
}
|
||||
|
||||
uint32_t writeMapEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeMapEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t writeListBegin(const TType elemType, const uint32_t size) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeListBegin_virt(elemType, size);
|
||||
}
|
||||
|
||||
uint32_t writeListEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeListEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t writeSetBegin(const TType elemType, const uint32_t size) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeSetBegin_virt(elemType, size);
|
||||
}
|
||||
|
||||
uint32_t writeSetEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeSetEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t writeBool(const bool value) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeBool_virt(value);
|
||||
}
|
||||
|
||||
uint32_t writeByte(const int8_t byte) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeByte_virt(byte);
|
||||
}
|
||||
|
||||
uint32_t writeI16(const int16_t i16) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeI16_virt(i16);
|
||||
}
|
||||
|
||||
uint32_t writeI32(const int32_t i32) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeI32_virt(i32);
|
||||
}
|
||||
|
||||
uint32_t writeI64(const int64_t i64) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeI64_virt(i64);
|
||||
}
|
||||
|
||||
uint32_t writeDouble(const double dub) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeDouble_virt(dub);
|
||||
}
|
||||
|
||||
uint32_t writeString(const std::string& str) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeString_virt(str);
|
||||
}
|
||||
|
||||
uint32_t writeBinary(const std::string& str) {
|
||||
T_VIRTUAL_CALL();
|
||||
return writeBinary_virt(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading functions
|
||||
*/
|
||||
|
||||
virtual uint32_t readMessageBegin(std::string& name,
|
||||
virtual uint32_t readMessageBegin_virt(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) = 0;
|
||||
|
||||
virtual uint32_t readMessageEnd() = 0;
|
||||
virtual uint32_t readMessageEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t readStructBegin(std::string& name) = 0;
|
||||
virtual uint32_t readStructBegin_virt(std::string& name) = 0;
|
||||
|
||||
virtual uint32_t readStructEnd() = 0;
|
||||
virtual uint32_t readStructEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t readFieldBegin(std::string& name,
|
||||
virtual uint32_t readFieldBegin_virt(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) = 0;
|
||||
|
||||
virtual uint32_t readFieldEnd() = 0;
|
||||
virtual uint32_t readFieldEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t readMapBegin(TType& keyType,
|
||||
virtual uint32_t readMapBegin_virt(TType& keyType,
|
||||
TType& valType,
|
||||
uint32_t& size) = 0;
|
||||
|
||||
virtual uint32_t readMapEnd() = 0;
|
||||
virtual uint32_t readMapEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t readListBegin(TType& elemType,
|
||||
virtual uint32_t readListBegin_virt(TType& elemType,
|
||||
uint32_t& size) = 0;
|
||||
|
||||
virtual uint32_t readListEnd() = 0;
|
||||
virtual uint32_t readListEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t readSetBegin(TType& elemType,
|
||||
virtual uint32_t readSetBegin_virt(TType& elemType,
|
||||
uint32_t& size) = 0;
|
||||
|
||||
virtual uint32_t readSetEnd() = 0;
|
||||
virtual uint32_t readSetEnd_virt() = 0;
|
||||
|
||||
virtual uint32_t readBool(bool& value) = 0;
|
||||
virtual uint32_t readBool_virt(bool& value) = 0;
|
||||
|
||||
virtual uint32_t readByte(int8_t& byte) = 0;
|
||||
virtual uint32_t readBool_virt(std::vector<bool>::reference value) = 0;
|
||||
|
||||
virtual uint32_t readI16(int16_t& i16) = 0;
|
||||
virtual uint32_t readByte_virt(int8_t& byte) = 0;
|
||||
|
||||
virtual uint32_t readI32(int32_t& i32) = 0;
|
||||
virtual uint32_t readI16_virt(int16_t& i16) = 0;
|
||||
|
||||
virtual uint32_t readI64(int64_t& i64) = 0;
|
||||
virtual uint32_t readI32_virt(int32_t& i32) = 0;
|
||||
|
||||
virtual uint32_t readDouble(double& dub) = 0;
|
||||
virtual uint32_t readI64_virt(int64_t& i64) = 0;
|
||||
|
||||
virtual uint32_t readString(std::string& str) = 0;
|
||||
virtual uint32_t readDouble_virt(double& dub) = 0;
|
||||
|
||||
virtual uint32_t readBinary(std::string& str) = 0;
|
||||
virtual uint32_t readString_virt(std::string& str) = 0;
|
||||
|
||||
uint32_t readBool(std::vector<bool>::reference ref) {
|
||||
bool value;
|
||||
uint32_t rv = readBool(value);
|
||||
ref = value;
|
||||
return rv;
|
||||
virtual uint32_t readBinary_virt(std::string& str) = 0;
|
||||
|
||||
uint32_t readMessageBegin(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readMessageBegin_virt(name, messageType, seqid);
|
||||
}
|
||||
|
||||
uint32_t readMessageEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return readMessageEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t readStructBegin(std::string& name) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readStructBegin_virt(name);
|
||||
}
|
||||
|
||||
uint32_t readStructEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return readStructEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t readFieldBegin(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readFieldBegin_virt(name, fieldType, fieldId);
|
||||
}
|
||||
|
||||
uint32_t readFieldEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return readFieldEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readMapBegin_virt(keyType, valType, size);
|
||||
}
|
||||
|
||||
uint32_t readMapEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return readMapEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t readListBegin(TType& elemType, uint32_t& size) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readListBegin_virt(elemType, size);
|
||||
}
|
||||
|
||||
uint32_t readListEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return readListEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t readSetBegin(TType& elemType, uint32_t& size) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readSetBegin_virt(elemType, size);
|
||||
}
|
||||
|
||||
uint32_t readSetEnd() {
|
||||
T_VIRTUAL_CALL();
|
||||
return readSetEnd_virt();
|
||||
}
|
||||
|
||||
uint32_t readBool(bool& value) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readBool_virt(value);
|
||||
}
|
||||
|
||||
uint32_t readByte(int8_t& byte) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readByte_virt(byte);
|
||||
}
|
||||
|
||||
uint32_t readI16(int16_t& i16) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readI16_virt(i16);
|
||||
}
|
||||
|
||||
uint32_t readI32(int32_t& i32) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readI32_virt(i32);
|
||||
}
|
||||
|
||||
uint32_t readI64(int64_t& i64) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readI64_virt(i64);
|
||||
}
|
||||
|
||||
uint32_t readDouble(double& dub) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readDouble_virt(dub);
|
||||
}
|
||||
|
||||
uint32_t readString(std::string& str) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readString_virt(str);
|
||||
}
|
||||
|
||||
uint32_t readBinary(std::string& str) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readBinary_virt(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* std::vector is specialized for bool, and its elements are individual bits
|
||||
* rather than bools. We need to define a different version of readBool()
|
||||
* to work with std::vector<bool>.
|
||||
*/
|
||||
uint32_t readBool(std::vector<bool>::reference value) {
|
||||
T_VIRTUAL_CALL();
|
||||
return readBool_virt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to arbitrarily skip over data.
|
||||
*/
|
||||
uint32_t skip(TType type) {
|
||||
switch (type) {
|
||||
case T_BOOL:
|
||||
{
|
||||
bool boolv;
|
||||
return readBool(boolv);
|
||||
}
|
||||
case T_BYTE:
|
||||
{
|
||||
int8_t bytev;
|
||||
return readByte(bytev);
|
||||
}
|
||||
case T_I16:
|
||||
{
|
||||
int16_t i16;
|
||||
return readI16(i16);
|
||||
}
|
||||
case T_I32:
|
||||
{
|
||||
int32_t i32;
|
||||
return readI32(i32);
|
||||
}
|
||||
case T_I64:
|
||||
{
|
||||
int64_t i64;
|
||||
return readI64(i64);
|
||||
}
|
||||
case T_DOUBLE:
|
||||
{
|
||||
double dub;
|
||||
return readDouble(dub);
|
||||
}
|
||||
case T_STRING:
|
||||
{
|
||||
std::string str;
|
||||
return readBinary(str);
|
||||
}
|
||||
case T_STRUCT:
|
||||
{
|
||||
uint32_t result = 0;
|
||||
std::string name;
|
||||
int16_t fid;
|
||||
TType ftype;
|
||||
result += readStructBegin(name);
|
||||
while (true) {
|
||||
result += readFieldBegin(name, ftype, fid);
|
||||
if (ftype == T_STOP) {
|
||||
break;
|
||||
}
|
||||
result += skip(ftype);
|
||||
result += readFieldEnd();
|
||||
}
|
||||
result += readStructEnd();
|
||||
return result;
|
||||
}
|
||||
case T_MAP:
|
||||
{
|
||||
uint32_t result = 0;
|
||||
TType keyType;
|
||||
TType valType;
|
||||
uint32_t i, size;
|
||||
result += readMapBegin(keyType, valType, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
result += skip(keyType);
|
||||
result += skip(valType);
|
||||
}
|
||||
result += readMapEnd();
|
||||
return result;
|
||||
}
|
||||
case T_SET:
|
||||
{
|
||||
uint32_t result = 0;
|
||||
TType elemType;
|
||||
uint32_t i, size;
|
||||
result += readSetBegin(elemType, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
result += skip(elemType);
|
||||
}
|
||||
result += readSetEnd();
|
||||
return result;
|
||||
}
|
||||
case T_LIST:
|
||||
{
|
||||
uint32_t result = 0;
|
||||
TType elemType;
|
||||
uint32_t i, size;
|
||||
result += readListBegin(elemType, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
result += skip(elemType);
|
||||
}
|
||||
result += readListEnd();
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
T_VIRTUAL_CALL();
|
||||
return skip_virt(type);
|
||||
}
|
||||
virtual uint32_t skip_virt(TType type) {
|
||||
return ::apache::thrift::protocol::skip(*this, type);
|
||||
}
|
||||
|
||||
inline boost::shared_ptr<TTransport> getTransport() {
|
||||
|
@ -414,11 +663,9 @@ class TProtocol {
|
|||
protected:
|
||||
TProtocol(boost::shared_ptr<TTransport> ptrans):
|
||||
ptrans_(ptrans) {
|
||||
trans_ = ptrans.get();
|
||||
}
|
||||
|
||||
boost::shared_ptr<TTransport> ptrans_;
|
||||
TTransport* trans_;
|
||||
|
||||
private:
|
||||
TProtocol() {}
|
||||
|
@ -436,6 +683,15 @@ class TProtocolFactory {
|
|||
virtual boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dummy protocol class.
|
||||
*
|
||||
* This class does nothing, and should never be instantiated.
|
||||
* It is used only by the generator code.
|
||||
*/
|
||||
class TDummyProtocol : public TProtocol {
|
||||
};
|
||||
|
||||
}}} // apache::thrift::protocol
|
||||
|
||||
#endif // #define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#ifndef _THRIFT_PROTOCOL_TPROTOCOLTAP_H_
|
||||
#define _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ 1
|
||||
|
||||
#include <protocol/TOneWayProtocol.h>
|
||||
#include <thrift/protocol/TVirtualProtocol.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
|
||||
|
@ -32,16 +32,16 @@ using apache::thrift::transport::TTransport;
|
|||
* second protocol object.
|
||||
*
|
||||
*/
|
||||
class TProtocolTap : public TReadOnlyProtocol {
|
||||
class TProtocolTap : public TVirtualProtocol<TProtocolTap> {
|
||||
public:
|
||||
TProtocolTap(boost::shared_ptr<TProtocol> source,
|
||||
boost::shared_ptr<TProtocol> sink)
|
||||
: TReadOnlyProtocol(source->getTransport(), "TProtocolTap")
|
||||
: TVirtualProtocol<TProtocolTap>(source->getTransport())
|
||||
, source_(source)
|
||||
, sink_(sink)
|
||||
{}
|
||||
|
||||
virtual uint32_t readMessageBegin(std::string& name,
|
||||
uint32_t readMessageBegin(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) {
|
||||
uint32_t rv = source_->readMessageBegin(name, messageType, seqid);
|
||||
|
@ -49,25 +49,25 @@ class TProtocolTap : public TReadOnlyProtocol {
|
|||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readMessageEnd() {
|
||||
uint32_t readMessageEnd() {
|
||||
uint32_t rv = source_->readMessageEnd();
|
||||
sink_->writeMessageEnd();
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readStructBegin(std::string& name) {
|
||||
uint32_t readStructBegin(std::string& name) {
|
||||
uint32_t rv = source_->readStructBegin(name);
|
||||
sink_->writeStructBegin(name.c_str());
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readStructEnd() {
|
||||
uint32_t readStructEnd() {
|
||||
uint32_t rv = source_->readStructEnd();
|
||||
sink_->writeStructEnd();
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readFieldBegin(std::string& name,
|
||||
uint32_t readFieldBegin(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) {
|
||||
uint32_t rv = source_->readFieldBegin(name, fieldType, fieldId);
|
||||
|
@ -80,13 +80,13 @@ class TProtocolTap : public TReadOnlyProtocol {
|
|||
}
|
||||
|
||||
|
||||
virtual uint32_t readFieldEnd() {
|
||||
uint32_t readFieldEnd() {
|
||||
uint32_t rv = source_->readFieldEnd();
|
||||
sink_->writeFieldEnd();
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readMapBegin(TType& keyType,
|
||||
uint32_t readMapBegin(TType& keyType,
|
||||
TType& valType,
|
||||
uint32_t& size) {
|
||||
uint32_t rv = source_->readMapBegin(keyType, valType, size);
|
||||
|
@ -95,83 +95,84 @@ class TProtocolTap : public TReadOnlyProtocol {
|
|||
}
|
||||
|
||||
|
||||
virtual uint32_t readMapEnd() {
|
||||
uint32_t readMapEnd() {
|
||||
uint32_t rv = source_->readMapEnd();
|
||||
sink_->writeMapEnd();
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readListBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
uint32_t readListBegin(TType& elemType, uint32_t& size) {
|
||||
uint32_t rv = source_->readListBegin(elemType, size);
|
||||
sink_->writeListBegin(elemType, size);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
virtual uint32_t readListEnd() {
|
||||
uint32_t readListEnd() {
|
||||
uint32_t rv = source_->readListEnd();
|
||||
sink_->writeListEnd();
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readSetBegin(TType& elemType,
|
||||
uint32_t& size) {
|
||||
uint32_t readSetBegin(TType& elemType, uint32_t& size) {
|
||||
uint32_t rv = source_->readSetBegin(elemType, size);
|
||||
sink_->writeSetBegin(elemType, size);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
virtual uint32_t readSetEnd() {
|
||||
uint32_t readSetEnd() {
|
||||
uint32_t rv = source_->readSetEnd();
|
||||
sink_->writeSetEnd();
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readBool(bool& value) {
|
||||
uint32_t readBool(bool& value) {
|
||||
uint32_t rv = source_->readBool(value);
|
||||
sink_->writeBool(value);
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readByte(int8_t& byte) {
|
||||
// Provide the default readBool() implementation for std::vector<bool>
|
||||
using TVirtualProtocol<TProtocolTap>::readBool;
|
||||
|
||||
uint32_t readByte(int8_t& byte) {
|
||||
uint32_t rv = source_->readByte(byte);
|
||||
sink_->writeByte(byte);
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readI16(int16_t& i16) {
|
||||
uint32_t readI16(int16_t& i16) {
|
||||
uint32_t rv = source_->readI16(i16);
|
||||
sink_->writeI16(i16);
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readI32(int32_t& i32) {
|
||||
uint32_t readI32(int32_t& i32) {
|
||||
uint32_t rv = source_->readI32(i32);
|
||||
sink_->writeI32(i32);
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readI64(int64_t& i64) {
|
||||
uint32_t readI64(int64_t& i64) {
|
||||
uint32_t rv = source_->readI64(i64);
|
||||
sink_->writeI64(i64);
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readDouble(double& dub) {
|
||||
uint32_t readDouble(double& dub) {
|
||||
uint32_t rv = source_->readDouble(dub);
|
||||
sink_->writeDouble(dub);
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readString(std::string& str) {
|
||||
uint32_t readString(std::string& str) {
|
||||
uint32_t rv = source_->readString(str);
|
||||
sink_->writeString(str);
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual uint32_t readBinary(std::string& str) {
|
||||
uint32_t readBinary(std::string& str) {
|
||||
uint32_t rv = source_->readBinary(str);
|
||||
sink_->writeBinary(str);
|
||||
return rv;
|
||||
|
|
564
nativeLib/org.apache.thrift/include/protocol/TVirtualProtocol.h
Normal file
564
nativeLib/org.apache.thrift/include/protocol/TVirtualProtocol.h
Normal file
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_
|
||||
#define _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1
|
||||
|
||||
#include <thrift/protocol/TProtocol.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
|
||||
using apache::thrift::transport::TTransport;
|
||||
|
||||
/**
|
||||
* Helper class that provides default implementations of TProtocol methods.
|
||||
*
|
||||
* This class provides default implementations of the non-virtual TProtocol
|
||||
* methods. It exists primarily so TVirtualProtocol can derive from it. It
|
||||
* prevents TVirtualProtocol methods from causing infinite recursion if the
|
||||
* non-virtual methods are not overridden by the TVirtualProtocol subclass.
|
||||
*
|
||||
* You probably don't want to use this class directly. Use TVirtualProtocol
|
||||
* instead.
|
||||
*/
|
||||
class TProtocolDefaults : public TProtocol {
|
||||
public:
|
||||
uint32_t readMessageBegin(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) {
|
||||
(void) name;
|
||||
(void) messageType;
|
||||
(void) seqid;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readMessageEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readStructBegin(std::string& name) {
|
||||
(void) name;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readStructEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readFieldBegin(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) {
|
||||
(void) name;
|
||||
(void) fieldType;
|
||||
(void) fieldId;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readFieldEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
|
||||
(void) keyType;
|
||||
(void) valType;
|
||||
(void) size;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readMapEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readListBegin(TType& elemType, uint32_t& size) {
|
||||
(void) elemType;
|
||||
(void) size;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readListEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readSetBegin(TType& elemType, uint32_t& size) {
|
||||
(void) elemType;
|
||||
(void) size;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readSetEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readBool(bool& value) {
|
||||
(void) value;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readBool(std::vector<bool>::reference value) {
|
||||
(void) value;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readByte(int8_t& byte) {
|
||||
(void) byte;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readI16(int16_t& i16) {
|
||||
(void) i16;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readI32(int32_t& i32) {
|
||||
(void) i32;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readI64(int64_t& i64) {
|
||||
(void) i64;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readDouble(double& dub) {
|
||||
(void) dub;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readString(std::string& str) {
|
||||
(void) str;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t readBinary(std::string& str) {
|
||||
(void) str;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support reading (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeMessageBegin(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) {
|
||||
(void) name;
|
||||
(void) messageType;
|
||||
(void) seqid;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeMessageEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
|
||||
uint32_t writeStructBegin(const char* name) {
|
||||
(void) name;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeStructEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeFieldBegin(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) {
|
||||
(void) name;
|
||||
(void) fieldType;
|
||||
(void) fieldId;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeFieldEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeFieldStop() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeMapBegin(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) {
|
||||
(void) keyType;
|
||||
(void) valType;
|
||||
(void) size;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeMapEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeListBegin(const TType elemType, const uint32_t size) {
|
||||
(void) elemType;
|
||||
(void) size;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeListEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeSetBegin(const TType elemType, const uint32_t size) {
|
||||
(void) elemType;
|
||||
(void) size;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeSetEnd() {
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeBool(const bool value) {
|
||||
(void) value;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeByte(const int8_t byte) {
|
||||
(void) byte;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeI16(const int16_t i16) {
|
||||
(void) i16;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeI32(const int32_t i32) {
|
||||
(void) i32;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeI64(const int64_t i64) {
|
||||
(void) i64;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeDouble(const double dub) {
|
||||
(void) dub;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeString(const std::string& str) {
|
||||
(void) str;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t writeBinary(const std::string& str) {
|
||||
(void) str;
|
||||
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
|
||||
"this protocol does not support writing (yet).");
|
||||
}
|
||||
|
||||
uint32_t skip(TType type) {
|
||||
return ::apache::thrift::protocol::skip(*this, type);
|
||||
}
|
||||
|
||||
protected:
|
||||
TProtocolDefaults(boost::shared_ptr<TTransport> ptrans)
|
||||
: TProtocol(ptrans)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* Concrete TProtocol classes should inherit from TVirtualProtocol
|
||||
* so they don't have to manually override virtual methods.
|
||||
*/
|
||||
template <class Protocol_, class Super_=TProtocolDefaults>
|
||||
class TVirtualProtocol : public Super_ {
|
||||
public:
|
||||
/**
|
||||
* Writing functions.
|
||||
*/
|
||||
|
||||
virtual uint32_t writeMessageBegin_virt(const std::string& name,
|
||||
const TMessageType messageType,
|
||||
const int32_t seqid) {
|
||||
return static_cast<Protocol_*>(this)->writeMessageBegin(name, messageType,
|
||||
seqid);
|
||||
}
|
||||
|
||||
virtual uint32_t writeMessageEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->writeMessageEnd();
|
||||
}
|
||||
|
||||
|
||||
virtual uint32_t writeStructBegin_virt(const char* name) {
|
||||
return static_cast<Protocol_*>(this)->writeStructBegin(name);
|
||||
}
|
||||
|
||||
virtual uint32_t writeStructEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->writeStructEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t writeFieldBegin_virt(const char* name,
|
||||
const TType fieldType,
|
||||
const int16_t fieldId) {
|
||||
return static_cast<Protocol_*>(this)->writeFieldBegin(name, fieldType,
|
||||
fieldId);
|
||||
}
|
||||
|
||||
virtual uint32_t writeFieldEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->writeFieldEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t writeFieldStop_virt() {
|
||||
return static_cast<Protocol_*>(this)->writeFieldStop();
|
||||
}
|
||||
|
||||
virtual uint32_t writeMapBegin_virt(const TType keyType,
|
||||
const TType valType,
|
||||
const uint32_t size) {
|
||||
return static_cast<Protocol_*>(this)->writeMapBegin(keyType, valType, size);
|
||||
}
|
||||
|
||||
virtual uint32_t writeMapEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->writeMapEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t writeListBegin_virt(const TType elemType,
|
||||
const uint32_t size) {
|
||||
return static_cast<Protocol_*>(this)->writeListBegin(elemType, size);
|
||||
}
|
||||
|
||||
virtual uint32_t writeListEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->writeListEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t writeSetBegin_virt(const TType elemType,
|
||||
const uint32_t size) {
|
||||
return static_cast<Protocol_*>(this)->writeSetBegin(elemType, size);
|
||||
}
|
||||
|
||||
virtual uint32_t writeSetEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->writeSetEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t writeBool_virt(const bool value) {
|
||||
return static_cast<Protocol_*>(this)->writeBool(value);
|
||||
}
|
||||
|
||||
virtual uint32_t writeByte_virt(const int8_t byte) {
|
||||
return static_cast<Protocol_*>(this)->writeByte(byte);
|
||||
}
|
||||
|
||||
virtual uint32_t writeI16_virt(const int16_t i16) {
|
||||
return static_cast<Protocol_*>(this)->writeI16(i16);
|
||||
}
|
||||
|
||||
virtual uint32_t writeI32_virt(const int32_t i32) {
|
||||
return static_cast<Protocol_*>(this)->writeI32(i32);
|
||||
}
|
||||
|
||||
virtual uint32_t writeI64_virt(const int64_t i64) {
|
||||
return static_cast<Protocol_*>(this)->writeI64(i64);
|
||||
}
|
||||
|
||||
virtual uint32_t writeDouble_virt(const double dub) {
|
||||
return static_cast<Protocol_*>(this)->writeDouble(dub);
|
||||
}
|
||||
|
||||
virtual uint32_t writeString_virt(const std::string& str) {
|
||||
return static_cast<Protocol_*>(this)->writeString(str);
|
||||
}
|
||||
|
||||
virtual uint32_t writeBinary_virt(const std::string& str) {
|
||||
return static_cast<Protocol_*>(this)->writeBinary(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading functions
|
||||
*/
|
||||
|
||||
virtual uint32_t readMessageBegin_virt(std::string& name,
|
||||
TMessageType& messageType,
|
||||
int32_t& seqid) {
|
||||
return static_cast<Protocol_*>(this)->readMessageBegin(name, messageType,
|
||||
seqid);
|
||||
}
|
||||
|
||||
virtual uint32_t readMessageEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->readMessageEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t readStructBegin_virt(std::string& name) {
|
||||
return static_cast<Protocol_*>(this)->readStructBegin(name);
|
||||
}
|
||||
|
||||
virtual uint32_t readStructEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->readStructEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t readFieldBegin_virt(std::string& name,
|
||||
TType& fieldType,
|
||||
int16_t& fieldId) {
|
||||
return static_cast<Protocol_*>(this)->readFieldBegin(name, fieldType,
|
||||
fieldId);
|
||||
}
|
||||
|
||||
virtual uint32_t readFieldEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->readFieldEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t readMapBegin_virt(TType& keyType,
|
||||
TType& valType,
|
||||
uint32_t& size) {
|
||||
return static_cast<Protocol_*>(this)->readMapBegin(keyType, valType, size);
|
||||
}
|
||||
|
||||
virtual uint32_t readMapEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->readMapEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t readListBegin_virt(TType& elemType,
|
||||
uint32_t& size) {
|
||||
return static_cast<Protocol_*>(this)->readListBegin(elemType, size);
|
||||
}
|
||||
|
||||
virtual uint32_t readListEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->readListEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t readSetBegin_virt(TType& elemType,
|
||||
uint32_t& size) {
|
||||
return static_cast<Protocol_*>(this)->readSetBegin(elemType, size);
|
||||
}
|
||||
|
||||
virtual uint32_t readSetEnd_virt() {
|
||||
return static_cast<Protocol_*>(this)->readSetEnd();
|
||||
}
|
||||
|
||||
virtual uint32_t readBool_virt(bool& value) {
|
||||
return static_cast<Protocol_*>(this)->readBool(value);
|
||||
}
|
||||
|
||||
virtual uint32_t readBool_virt(std::vector<bool>::reference value) {
|
||||
return static_cast<Protocol_*>(this)->readBool(value);
|
||||
}
|
||||
|
||||
virtual uint32_t readByte_virt(int8_t& byte) {
|
||||
return static_cast<Protocol_*>(this)->readByte(byte);
|
||||
}
|
||||
|
||||
virtual uint32_t readI16_virt(int16_t& i16) {
|
||||
return static_cast<Protocol_*>(this)->readI16(i16);
|
||||
}
|
||||
|
||||
virtual uint32_t readI32_virt(int32_t& i32) {
|
||||
return static_cast<Protocol_*>(this)->readI32(i32);
|
||||
}
|
||||
|
||||
virtual uint32_t readI64_virt(int64_t& i64) {
|
||||
return static_cast<Protocol_*>(this)->readI64(i64);
|
||||
}
|
||||
|
||||
virtual uint32_t readDouble_virt(double& dub) {
|
||||
return static_cast<Protocol_*>(this)->readDouble(dub);
|
||||
}
|
||||
|
||||
virtual uint32_t readString_virt(std::string& str) {
|
||||
return static_cast<Protocol_*>(this)->readString(str);
|
||||
}
|
||||
|
||||
virtual uint32_t readBinary_virt(std::string& str) {
|
||||
return static_cast<Protocol_*>(this)->readBinary(str);
|
||||
}
|
||||
|
||||
virtual uint32_t skip_virt(TType type) {
|
||||
return static_cast<Protocol_*>(this)->skip(type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide a default skip() implementation that uses non-virtual read
|
||||
* methods.
|
||||
*
|
||||
* Note: subclasses that use TVirtualProtocol to derive from another protocol
|
||||
* implementation (i.e., not TProtocolDefaults) should beware that this may
|
||||
* override any non-default skip() implementation provided by the parent
|
||||
* transport class. They may need to explicitly redefine skip() to call the
|
||||
* correct parent implementation, if desired.
|
||||
*/
|
||||
uint32_t skip(TType type) {
|
||||
Protocol_* const prot = static_cast<Protocol_*>(this);
|
||||
return ::apache::thrift::protocol::skip(*prot, type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide a default readBool() implementation for use with
|
||||
* std::vector<bool>, that behaves the same as reading into a normal bool.
|
||||
*
|
||||
* Subclasses can override this if desired, but there normally shouldn't
|
||||
* be a need to.
|
||||
*/
|
||||
uint32_t readBool(std::vector<bool>::reference value) {
|
||||
bool b = false;
|
||||
uint32_t ret = static_cast<Protocol_*>(this)->readBool(b);
|
||||
value = b;
|
||||
return ret;
|
||||
}
|
||||
using Super_::readBool; // so we don't hide readBool(bool&)
|
||||
|
||||
protected:
|
||||
TVirtualProtocol(boost::shared_ptr<TTransport> ptrans)
|
||||
: Super_(ptrans)
|
||||
{}
|
||||
};
|
||||
|
||||
}}} // apache::thrift::protocol
|
||||
|
||||
#endif // #define _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1
|
179
nativeLib/org.apache.thrift/include/qt/TQIODeviceTransport.cpp
Normal file
179
nativeLib/org.apache.thrift/include/qt/TQIODeviceTransport.cpp
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <thrift/qt/TQIODeviceTransport.h>
|
||||
|
||||
#include <QAbstractSocket>
|
||||
#include <QIODevice>
|
||||
|
||||
#include <thrift/transport/TBufferTransports.h>
|
||||
|
||||
using boost::shared_ptr;
|
||||
|
||||
namespace apache { namespace thrift { namespace transport {
|
||||
|
||||
TQIODeviceTransport::TQIODeviceTransport(shared_ptr<QIODevice> dev)
|
||||
: dev_(dev)
|
||||
{
|
||||
}
|
||||
|
||||
TQIODeviceTransport::~TQIODeviceTransport()
|
||||
{
|
||||
dev_->close();
|
||||
}
|
||||
|
||||
void TQIODeviceTransport::open()
|
||||
{
|
||||
if (!isOpen()) {
|
||||
throw TTransportException(TTransportException::NOT_OPEN,
|
||||
"open(): underlying QIODevice isn't open");
|
||||
}
|
||||
}
|
||||
|
||||
bool TQIODeviceTransport::isOpen()
|
||||
{
|
||||
return dev_->isOpen();
|
||||
}
|
||||
|
||||
bool TQIODeviceTransport::peek()
|
||||
{
|
||||
return dev_->bytesAvailable() > 0;
|
||||
}
|
||||
|
||||
void TQIODeviceTransport::close()
|
||||
{
|
||||
dev_->close();
|
||||
}
|
||||
|
||||
uint32_t TQIODeviceTransport::readAll(uint8_t* buf, uint32_t len)
|
||||
{
|
||||
uint32_t requestLen = len;
|
||||
while (len) {
|
||||
uint32_t readSize;
|
||||
try {
|
||||
readSize = read(buf, len);
|
||||
} catch (...) {
|
||||
if (len != requestLen) {
|
||||
// something read already
|
||||
return requestLen - len;
|
||||
}
|
||||
// error but nothing read yet
|
||||
throw;
|
||||
}
|
||||
if (readSize == 0) {
|
||||
dev_->waitForReadyRead(50);
|
||||
} else {
|
||||
buf += readSize;
|
||||
len -= readSize;
|
||||
}
|
||||
}
|
||||
return requestLen;
|
||||
}
|
||||
|
||||
uint32_t TQIODeviceTransport::read(uint8_t* buf, uint32_t len)
|
||||
{
|
||||
uint32_t actualSize;
|
||||
qint64 readSize;
|
||||
|
||||
if (!dev_->isOpen()) {
|
||||
throw TTransportException(TTransportException::NOT_OPEN,
|
||||
"read(): underlying QIODevice is not open");
|
||||
}
|
||||
|
||||
actualSize = (uint32_t)std::min((qint64)len, dev_->bytesAvailable());
|
||||
readSize = dev_->read(reinterpret_cast<char *>(buf), actualSize);
|
||||
|
||||
if (readSize < 0) {
|
||||
QAbstractSocket* socket;
|
||||
if ((socket = qobject_cast<QAbstractSocket* >(dev_.get()))) {
|
||||
throw TTransportException(TTransportException::UNKNOWN,
|
||||
"Failed to read() from QAbstractSocket",
|
||||
socket->error());
|
||||
}
|
||||
throw TTransportException(TTransportException::UNKNOWN,
|
||||
"Failed to read from from QIODevice");
|
||||
}
|
||||
|
||||
return (uint32_t)readSize;
|
||||
}
|
||||
|
||||
void TQIODeviceTransport::write(const uint8_t* buf, uint32_t len)
|
||||
{
|
||||
while (len) {
|
||||
uint32_t written = write_partial(buf, len);
|
||||
len -= written;
|
||||
dev_->waitForBytesWritten(50);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TQIODeviceTransport::write_partial(const uint8_t* buf, uint32_t len)
|
||||
{
|
||||
qint64 written;
|
||||
|
||||
if (!dev_->isOpen()) {
|
||||
throw TTransportException(TTransportException::NOT_OPEN,
|
||||
"write_partial(): underlying QIODevice is not open");
|
||||
}
|
||||
|
||||
written = dev_->write(reinterpret_cast<const char*>(buf), len);
|
||||
if (written < 0) {
|
||||
QAbstractSocket* socket;
|
||||
if ((socket = qobject_cast<QAbstractSocket*>(dev_.get()))) {
|
||||
throw TTransportException(TTransportException::UNKNOWN,
|
||||
"write_partial(): failed to write to QAbstractSocket", socket->error());
|
||||
}
|
||||
|
||||
throw TTransportException(TTransportException::UNKNOWN,
|
||||
"write_partial(): failed to write to underlying QIODevice");
|
||||
}
|
||||
|
||||
return (uint32_t)written;
|
||||
}
|
||||
|
||||
void TQIODeviceTransport::flush()
|
||||
{
|
||||
if (!dev_->isOpen()) {
|
||||
throw TTransportException(TTransportException::NOT_OPEN,
|
||||
"flush(): underlying QIODevice is not open");
|
||||
}
|
||||
|
||||
QAbstractSocket* socket;
|
||||
|
||||
if ((socket = qobject_cast<QAbstractSocket*>(dev_.get()))) {
|
||||
socket->flush();
|
||||
} else {
|
||||
dev_->waitForBytesWritten(1);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* TQIODeviceTransport::borrow(uint8_t* buf, uint32_t* len)
|
||||
{
|
||||
(void) buf;
|
||||
(void) len;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void TQIODeviceTransport::consume(uint32_t len)
|
||||
{
|
||||
(void) len;
|
||||
throw TTransportException(TTransportException::UNKNOWN);
|
||||
}
|
||||
|
||||
}}} // apache::thrift::transport
|
||||
|
64
nativeLib/org.apache.thrift/include/qt/TQIODeviceTransport.h
Normal file
64
nativeLib/org.apache.thrift/include/qt/TQIODeviceTransport.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_
|
||||
#define _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_ 1
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <thrift/transport/TVirtualTransport.h>
|
||||
|
||||
class QIODevice;
|
||||
|
||||
namespace apache { namespace thrift { namespace transport {
|
||||
|
||||
/**
|
||||
* Transport that operates on a QIODevice (socket, file, etc).
|
||||
*/
|
||||
class TQIODeviceTransport : public apache::thrift::transport::TVirtualTransport<TQIODeviceTransport> {
|
||||
public:
|
||||
explicit TQIODeviceTransport(boost::shared_ptr<QIODevice> dev);
|
||||
virtual ~TQIODeviceTransport();
|
||||
|
||||
void open();
|
||||
bool isOpen();
|
||||
bool peek();
|
||||
void close();
|
||||
|
||||
uint32_t readAll(uint8_t *buf, uint32_t len);
|
||||
uint32_t read(uint8_t* buf, uint32_t len);
|
||||
|
||||
void write(const uint8_t* buf, uint32_t len);
|
||||
uint32_t write_partial(const uint8_t* buf, uint32_t len);
|
||||
|
||||
void flush();
|
||||
|
||||
uint8_t* borrow(uint8_t* buf, uint32_t* len);
|
||||
void consume(uint32_t len);
|
||||
|
||||
private:
|
||||
TQIODeviceTransport(const TQIODeviceTransport&);
|
||||
TQIODeviceTransport& operator=(const TQIODeviceTransport&);
|
||||
|
||||
boost::shared_ptr<QIODevice> dev_;
|
||||
};
|
||||
}}} // apache::thrift::transport
|
||||
|
||||
#endif // #ifndef _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_
|
||||
|
157
nativeLib/org.apache.thrift/include/qt/TQTcpServer.cpp
Normal file
157
nativeLib/org.apache.thrift/include/qt/TQTcpServer.cpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "TQTcpServer.h"
|
||||
#include "TQIODeviceTransport.h"
|
||||
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include <tr1/functional>
|
||||
|
||||
#include <thrift/protocol/TProtocol.h>
|
||||
#include <thrift/async/TAsyncProcessor.h>
|
||||
|
||||
using boost::shared_ptr;
|
||||
using apache::thrift::protocol::TProtocol;
|
||||
using apache::thrift::protocol::TProtocolFactory;
|
||||
using apache::thrift::transport::TTransport;
|
||||
using apache::thrift::transport::TTransportException;
|
||||
using apache::thrift::transport::TQIODeviceTransport;
|
||||
using std::tr1::function;
|
||||
using std::tr1::bind;
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
struct TQTcpServer::ConnectionContext {
|
||||
shared_ptr<QTcpSocket> connection_;
|
||||
shared_ptr<TTransport> transport_;
|
||||
shared_ptr<TProtocol> iprot_;
|
||||
shared_ptr<TProtocol> oprot_;
|
||||
|
||||
explicit ConnectionContext(shared_ptr<QTcpSocket> connection,
|
||||
shared_ptr<TTransport> transport,
|
||||
shared_ptr<TProtocol> iprot,
|
||||
shared_ptr<TProtocol> oprot)
|
||||
: connection_(connection)
|
||||
, transport_(transport)
|
||||
, iprot_(iprot)
|
||||
, oprot_(oprot)
|
||||
{}
|
||||
};
|
||||
|
||||
TQTcpServer::TQTcpServer(shared_ptr<QTcpServer> server,
|
||||
shared_ptr<TAsyncProcessor> processor,
|
||||
shared_ptr<TProtocolFactory> pfact,
|
||||
QObject* parent)
|
||||
: QObject(parent)
|
||||
, server_(server)
|
||||
, processor_(processor)
|
||||
, pfact_(pfact)
|
||||
{
|
||||
connect(server.get(), SIGNAL(newConnection()), SLOT(processIncoming()));
|
||||
}
|
||||
|
||||
TQTcpServer::~TQTcpServer()
|
||||
{
|
||||
}
|
||||
|
||||
void TQTcpServer::processIncoming()
|
||||
{
|
||||
while (server_->hasPendingConnections()) {
|
||||
// take ownership of the QTcpSocket; technically it could be deleted
|
||||
// when the QTcpServer is destroyed, but any real app should delete this
|
||||
// class before deleting the QTcpServer that we are using
|
||||
shared_ptr<QTcpSocket> connection(server_->nextPendingConnection());
|
||||
|
||||
shared_ptr<TTransport> transport;
|
||||
shared_ptr<TProtocol> iprot;
|
||||
shared_ptr<TProtocol> oprot;
|
||||
|
||||
try {
|
||||
transport = shared_ptr<TTransport>(new TQIODeviceTransport(connection));
|
||||
iprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
|
||||
oprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
|
||||
} catch(...) {
|
||||
qWarning("[TQTcpServer] Failed to initialize transports/protocols");
|
||||
continue;
|
||||
}
|
||||
|
||||
ctxMap_[connection.get()] =
|
||||
shared_ptr<ConnectionContext>(
|
||||
new ConnectionContext(connection, transport, iprot, oprot));
|
||||
|
||||
connect(connection.get(), SIGNAL(readyRead()), SLOT(beginDecode()));
|
||||
|
||||
// need to use QueuedConnection since we will be deleting the socket in the slot
|
||||
connect(connection.get(), SIGNAL(disconnected()), SLOT(socketClosed()),
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void TQTcpServer::beginDecode()
|
||||
{
|
||||
QTcpSocket* connection(qobject_cast<QTcpSocket*>(sender()));
|
||||
Q_ASSERT(connection);
|
||||
|
||||
if (ctxMap_.find(connection) == ctxMap_.end()) {
|
||||
qWarning("[TQTcpServer] Got data on an unknown QTcpSocket");
|
||||
return;
|
||||
}
|
||||
|
||||
shared_ptr<ConnectionContext> ctx = ctxMap_[connection];
|
||||
|
||||
try {
|
||||
processor_->process(
|
||||
bind(&TQTcpServer::finish, this,
|
||||
ctx, std::tr1::placeholders::_1),
|
||||
ctx->iprot_, ctx->oprot_);
|
||||
} catch(const TTransportException& ex) {
|
||||
qWarning("[TQTcpServer] TTransportException during processing: '%s'",
|
||||
ex.what());
|
||||
ctxMap_.erase(connection);
|
||||
} catch(...) {
|
||||
qWarning("[TQTcpServer] Unknown processor exception");
|
||||
ctxMap_.erase(connection);
|
||||
}
|
||||
}
|
||||
|
||||
void TQTcpServer::socketClosed()
|
||||
{
|
||||
QTcpSocket* connection(qobject_cast<QTcpSocket*>(sender()));
|
||||
Q_ASSERT(connection);
|
||||
|
||||
if (ctxMap_.find(connection) == ctxMap_.end()) {
|
||||
qWarning("[TQTcpServer] Unknown QTcpSocket closed");
|
||||
return;
|
||||
}
|
||||
|
||||
ctxMap_.erase(connection);
|
||||
}
|
||||
|
||||
void TQTcpServer::finish(shared_ptr<ConnectionContext> ctx, bool healthy)
|
||||
{
|
||||
if (!healthy) {
|
||||
qWarning("[TQTcpServer] Processor failed to process data successfully");
|
||||
ctxMap_.erase(ctx->connection_.get());
|
||||
}
|
||||
}
|
||||
|
||||
}}} // apache::thrift::async
|
72
nativeLib/org.apache.thrift/include/qt/TQTcpServer.h
Normal file
72
nativeLib/org.apache.thrift/include/qt/TQTcpServer.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _THRIFT_TASYNC_QTCP_SERVER_H_
|
||||
#define _THRIFT_TASYNC_QTCP_SERVER_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QTcpServer>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace apache { namespace thrift { namespace protocol {
|
||||
class TProtocolFactory;
|
||||
}}} // apache::thrift::protocol
|
||||
|
||||
namespace apache { namespace thrift { namespace async {
|
||||
|
||||
class TAsyncProcessor;
|
||||
|
||||
/**
|
||||
* Server that uses Qt to listen for connections.
|
||||
* Simply give it a QTcpServer that is listening, along with an async
|
||||
* processor and a protocol factory, and then run the Qt event loop.
|
||||
*/
|
||||
class TQTcpServer : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TQTcpServer(boost::shared_ptr<QTcpServer> server,
|
||||
boost::shared_ptr<TAsyncProcessor> processor,
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> protocolFactory,
|
||||
QT_PREPEND_NAMESPACE(QObject)* parent = NULL);
|
||||
virtual ~TQTcpServer();
|
||||
|
||||
private Q_SLOTS:
|
||||
void processIncoming();
|
||||
void beginDecode();
|
||||
void socketClosed();
|
||||
|
||||
private:
|
||||
TQTcpServer(const TQTcpServer&);
|
||||
TQTcpServer& operator=(const TQTcpServer&);
|
||||
|
||||
class ConnectionContext;
|
||||
|
||||
void finish(boost::shared_ptr<ConnectionContext> ctx, bool healthy);
|
||||
|
||||
boost::shared_ptr<QTcpServer> server_;
|
||||
boost::shared_ptr<TAsyncProcessor> processor_;
|
||||
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact_;
|
||||
|
||||
std::map<QT_PREPEND_NAMESPACE(QTcpSocket)*, boost::shared_ptr<ConnectionContext> > ctxMap_;
|
||||
};
|
||||
|
||||
}}} // apache::thrift::async
|
||||
|
||||
#endif // #ifndef _THRIFT_TASYNC_QTCP_SERVER_H_
|
100
nativeLib/org.apache.thrift/include/qt/moc_TQTcpServer.cpp
Normal file
100
nativeLib/org.apache.thrift/include/qt/moc_TQTcpServer.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
/****************************************************************************
|
||||
** Meta object code from reading C++ file 'TQTcpServer.h'
|
||||
**
|
||||
** Created: Thu Oct 11 18:00:54 2012
|
||||
** by: The Qt Meta Object Compiler version 63 (Qt 4.8.1)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
*****************************************************************************/
|
||||
|
||||
#include "TQTcpServer.h"
|
||||
#if !defined(Q_MOC_OUTPUT_REVISION)
|
||||
#error "The header file 'TQTcpServer.h' doesn't include <QObject>."
|
||||
#elif Q_MOC_OUTPUT_REVISION != 63
|
||||
#error "This file was generated using the moc from 4.8.1. It"
|
||||
#error "cannot be used with the include files from this version of Qt."
|
||||
#error "(The moc has changed too much.)"
|
||||
#endif
|
||||
|
||||
QT_BEGIN_MOC_NAMESPACE
|
||||
static const uint qt_meta_data_apache__thrift__async__TQTcpServer[] = {
|
||||
|
||||
// content:
|
||||
6, // revision
|
||||
0, // classname
|
||||
0, 0, // classinfo
|
||||
3, 14, // methods
|
||||
0, 0, // properties
|
||||
0, 0, // enums/sets
|
||||
0, 0, // constructors
|
||||
0, // flags
|
||||
0, // signalCount
|
||||
|
||||
// slots: signature, parameters, type, tag, flags
|
||||
36, 35, 35, 35, 0x08,
|
||||
54, 35, 35, 35, 0x08,
|
||||
68, 35, 35, 35, 0x08,
|
||||
|
||||
0 // eod
|
||||
};
|
||||
|
||||
static const char qt_meta_stringdata_apache__thrift__async__TQTcpServer[] = {
|
||||
"apache::thrift::async::TQTcpServer\0\0"
|
||||
"processIncoming()\0beginDecode()\0"
|
||||
"socketClosed()\0"
|
||||
};
|
||||
|
||||
void apache::thrift::async::TQTcpServer::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
|
||||
{
|
||||
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||
Q_ASSERT(staticMetaObject.cast(_o));
|
||||
TQTcpServer *_t = static_cast<TQTcpServer *>(_o);
|
||||
switch (_id) {
|
||||
case 0: _t->processIncoming(); break;
|
||||
case 1: _t->beginDecode(); break;
|
||||
case 2: _t->socketClosed(); break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
Q_UNUSED(_a);
|
||||
}
|
||||
|
||||
const QMetaObjectExtraData apache::thrift::async::TQTcpServer::staticMetaObjectExtraData = {
|
||||
0, qt_static_metacall
|
||||
};
|
||||
|
||||
const QMetaObject apache::thrift::async::TQTcpServer::staticMetaObject = {
|
||||
{ &QObject::staticMetaObject, qt_meta_stringdata_apache__thrift__async__TQTcpServer,
|
||||
qt_meta_data_apache__thrift__async__TQTcpServer, &staticMetaObjectExtraData }
|
||||
};
|
||||
|
||||
#ifdef Q_NO_DATA_RELOCATION
|
||||
const QMetaObject &apache::thrift::async::TQTcpServer::getStaticMetaObject() { return staticMetaObject; }
|
||||
#endif //Q_NO_DATA_RELOCATION
|
||||
|
||||
const QMetaObject *apache::thrift::async::TQTcpServer::metaObject() const
|
||||
{
|
||||
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
|
||||
}
|
||||
|
||||
void *apache::thrift::async::TQTcpServer::qt_metacast(const char *_clname)
|
||||
{
|
||||
if (!_clname) return 0;
|
||||
if (!strcmp(_clname, qt_meta_stringdata_apache__thrift__async__TQTcpServer))
|
||||
return static_cast<void*>(const_cast< TQTcpServer*>(this));
|
||||
return QObject::qt_metacast(_clname);
|
||||
}
|
||||
|
||||
int apache::thrift::async::TQTcpServer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
{
|
||||
_id = QObject::qt_metacall(_c, _id, _a);
|
||||
if (_id < 0)
|
||||
return _id;
|
||||
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||
if (_id < 3)
|
||||
qt_static_metacall(this, _c, _id, _a);
|
||||
_id -= 3;
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
QT_END_MOC_NAMESPACE
|
1539
nativeLib/org.apache.thrift/include/server/TNonblockingServer.cpp
Normal file
1539
nativeLib/org.apache.thrift/include/server/TNonblockingServer.cpp
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
49
nativeLib/org.apache.thrift/include/server/TServer.cpp
Normal file
49
nativeLib/org.apache.thrift/include/server/TServer.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace apache { namespace thrift { namespace server {
|
||||
|
||||
int increase_max_fds(int max_fds=(1<<24)) {
|
||||
struct rlimit fdmaxrl;
|
||||
|
||||
for(fdmaxrl.rlim_cur = max_fds, fdmaxrl.rlim_max = max_fds;
|
||||
max_fds && (setrlimit(RLIMIT_NOFILE, &fdmaxrl) < 0);
|
||||
fdmaxrl.rlim_cur = max_fds, fdmaxrl.rlim_max = max_fds) {
|
||||
max_fds /= 2;
|
||||
}
|
||||
|
||||
return fdmaxrl.rlim_cur;
|
||||
}
|
||||
|
||||
}}} // apache::thrift::server
|
|
@ -20,10 +20,10 @@
|
|||
#ifndef _THRIFT_SERVER_TSERVER_H_
|
||||
#define _THRIFT_SERVER_TSERVER_H_ 1
|
||||
|
||||
#include <TProcessor.h>
|
||||
#include <transport/TServerTransport.h>
|
||||
#include <protocol/TBinaryProtocol.h>
|
||||
#include <concurrency/Thread.h>
|
||||
#include <thrift/TProcessor.h>
|
||||
#include <thrift/transport/TServerTransport.h>
|
||||
#include <thrift/protocol/TBinaryProtocol.h>
|
||||
#include <thrift/concurrency/Thread.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
@ -57,14 +57,33 @@ class TServerEventHandler {
|
|||
/**
|
||||
* Called when a new client has connected and is about to being processing.
|
||||
*/
|
||||
virtual void clientBegin(boost::shared_ptr<TProtocol> /* input */,
|
||||
boost::shared_ptr<TProtocol> /* output */) {}
|
||||
virtual void* createContext(boost::shared_ptr<TProtocol> input,
|
||||
boost::shared_ptr<TProtocol> output) {
|
||||
(void)input;
|
||||
(void)output;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a client has finished making requests.
|
||||
* Called when a client has finished request-handling to delete server
|
||||
* context.
|
||||
*/
|
||||
virtual void clientEnd(boost::shared_ptr<TProtocol> /* input */,
|
||||
boost::shared_ptr<TProtocol> /* output */) {}
|
||||
virtual void deleteContext(void* serverContext,
|
||||
boost::shared_ptr<TProtocol>input,
|
||||
boost::shared_ptr<TProtocol>output) {
|
||||
(void)serverContext;
|
||||
(void)input;
|
||||
(void)output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a client is about to call the processor.
|
||||
*/
|
||||
virtual void processContext(void* serverContext,
|
||||
boost::shared_ptr<TTransport> transport) {
|
||||
(void)serverContext;
|
||||
(void)transport;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -93,8 +112,8 @@ class TServer : public concurrency::Runnable {
|
|||
serve();
|
||||
}
|
||||
|
||||
boost::shared_ptr<TProcessor> getProcessor() {
|
||||
return processor_;
|
||||
boost::shared_ptr<TProcessorFactory> getProcessorFactory() {
|
||||
return processorFactory_;
|
||||
}
|
||||
|
||||
boost::shared_ptr<TServerTransport> getServerTransport() {
|
||||
|
@ -122,17 +141,51 @@ class TServer : public concurrency::Runnable {
|
|||
}
|
||||
|
||||
protected:
|
||||
TServer(boost::shared_ptr<TProcessor> processor):
|
||||
processor_(processor) {
|
||||
template<typename ProcessorFactory>
|
||||
TServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)):
|
||||
processorFactory_(processorFactory) {
|
||||
setInputTransportFactory(boost::shared_ptr<TTransportFactory>(
|
||||
new TTransportFactory()));
|
||||
setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(
|
||||
new TTransportFactory()));
|
||||
setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(
|
||||
new TBinaryProtocolFactory()));
|
||||
setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(
|
||||
new TBinaryProtocolFactory()));
|
||||
}
|
||||
|
||||
template<typename Processor>
|
||||
TServer(const boost::shared_ptr<Processor>& processor,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor)):
|
||||
processorFactory_(new TSingletonProcessorFactory(processor)) {
|
||||
setInputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
|
||||
setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
|
||||
setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
|
||||
setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
|
||||
}
|
||||
|
||||
TServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport):
|
||||
processor_(processor),
|
||||
template<typename ProcessorFactory>
|
||||
TServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)):
|
||||
processorFactory_(processorFactory),
|
||||
serverTransport_(serverTransport) {
|
||||
setInputTransportFactory(boost::shared_ptr<TTransportFactory>(
|
||||
new TTransportFactory()));
|
||||
setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(
|
||||
new TTransportFactory()));
|
||||
setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(
|
||||
new TBinaryProtocolFactory()));
|
||||
setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(
|
||||
new TBinaryProtocolFactory()));
|
||||
}
|
||||
|
||||
template<typename Processor>
|
||||
TServer(const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor)):
|
||||
processorFactory_(new TSingletonProcessorFactory(processor)),
|
||||
serverTransport_(serverTransport) {
|
||||
setInputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
|
||||
setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
|
||||
|
@ -140,33 +193,82 @@ protected:
|
|||
setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
|
||||
}
|
||||
|
||||
TServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport,
|
||||
boost::shared_ptr<TTransportFactory> transportFactory,
|
||||
boost::shared_ptr<TProtocolFactory> protocolFactory):
|
||||
processor_(processor),
|
||||
template<typename ProcessorFactory>
|
||||
TServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)):
|
||||
processorFactory_(processorFactory),
|
||||
serverTransport_(serverTransport),
|
||||
inputTransportFactory_(transportFactory),
|
||||
outputTransportFactory_(transportFactory),
|
||||
inputProtocolFactory_(protocolFactory),
|
||||
outputProtocolFactory_(protocolFactory) {}
|
||||
|
||||
TServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport,
|
||||
boost::shared_ptr<TTransportFactory> inputTransportFactory,
|
||||
boost::shared_ptr<TTransportFactory> outputTransportFactory,
|
||||
boost::shared_ptr<TProtocolFactory> inputProtocolFactory,
|
||||
boost::shared_ptr<TProtocolFactory> outputProtocolFactory):
|
||||
processor_(processor),
|
||||
template<typename Processor>
|
||||
TServer(const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor)):
|
||||
processorFactory_(new TSingletonProcessorFactory(processor)),
|
||||
serverTransport_(serverTransport),
|
||||
inputTransportFactory_(transportFactory),
|
||||
outputTransportFactory_(transportFactory),
|
||||
inputProtocolFactory_(protocolFactory),
|
||||
outputProtocolFactory_(protocolFactory) {}
|
||||
|
||||
template<typename ProcessorFactory>
|
||||
TServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
|
||||
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)):
|
||||
processorFactory_(processorFactory),
|
||||
serverTransport_(serverTransport),
|
||||
inputTransportFactory_(inputTransportFactory),
|
||||
outputTransportFactory_(outputTransportFactory),
|
||||
inputProtocolFactory_(inputProtocolFactory),
|
||||
outputProtocolFactory_(outputProtocolFactory) {}
|
||||
|
||||
template<typename Processor>
|
||||
TServer(const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
|
||||
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor)):
|
||||
processorFactory_(new TSingletonProcessorFactory(processor)),
|
||||
serverTransport_(serverTransport),
|
||||
inputTransportFactory_(inputTransportFactory),
|
||||
outputTransportFactory_(outputTransportFactory),
|
||||
inputProtocolFactory_(inputProtocolFactory),
|
||||
outputProtocolFactory_(outputProtocolFactory) {}
|
||||
|
||||
/**
|
||||
* Get a TProcessor to handle calls on a particular connection.
|
||||
*
|
||||
* This method should only be called once per connection (never once per
|
||||
* call). This allows the TProcessorFactory to return a different processor
|
||||
* for each connection if it desires.
|
||||
*/
|
||||
boost::shared_ptr<TProcessor> getProcessor(
|
||||
boost::shared_ptr<TProtocol> inputProtocol,
|
||||
boost::shared_ptr<TProtocol> outputProtocol,
|
||||
boost::shared_ptr<TTransport> transport) {
|
||||
TConnectionInfo connInfo;
|
||||
connInfo.input = inputProtocol;
|
||||
connInfo.output = outputProtocol;
|
||||
connInfo.transport = transport;
|
||||
return processorFactory_->getProcessor(connInfo);
|
||||
}
|
||||
|
||||
// Class variables
|
||||
boost::shared_ptr<TProcessor> processor_;
|
||||
boost::shared_ptr<TProcessorFactory> processorFactory_;
|
||||
boost::shared_ptr<TServerTransport> serverTransport_;
|
||||
|
||||
boost::shared_ptr<TTransportFactory> inputTransportFactory_;
|
||||
|
|
153
nativeLib/org.apache.thrift/include/server/TSimpleServer.cpp
Normal file
153
nativeLib/org.apache.thrift/include/server/TSimpleServer.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <thrift/server/TSimpleServer.h>
|
||||
#include <thrift/transport/TTransportException.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace apache { namespace thrift { namespace server {
|
||||
|
||||
using namespace std;
|
||||
using namespace apache::thrift;
|
||||
using namespace apache::thrift::protocol;
|
||||
using namespace apache::thrift::transport;
|
||||
using boost::shared_ptr;
|
||||
|
||||
/**
|
||||
* A simple single-threaded application server. Perfect for unit tests!
|
||||
*
|
||||
*/
|
||||
void TSimpleServer::serve() {
|
||||
|
||||
shared_ptr<TTransport> client;
|
||||
shared_ptr<TTransport> inputTransport;
|
||||
shared_ptr<TTransport> outputTransport;
|
||||
shared_ptr<TProtocol> inputProtocol;
|
||||
shared_ptr<TProtocol> outputProtocol;
|
||||
|
||||
// Start the server listening
|
||||
serverTransport_->listen();
|
||||
|
||||
// Run the preServe event
|
||||
if (eventHandler_ != NULL) {
|
||||
eventHandler_->preServe();
|
||||
}
|
||||
|
||||
// Fetch client from server
|
||||
while (!stop_) {
|
||||
try {
|
||||
client = serverTransport_->accept();
|
||||
inputTransport = inputTransportFactory_->getTransport(client);
|
||||
outputTransport = outputTransportFactory_->getTransport(client);
|
||||
inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
|
||||
outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
|
||||
} catch (TTransportException& ttx) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED) {
|
||||
string errStr = string("TServerTransport died on accept: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
continue;
|
||||
} catch (TException& tx) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
string errStr = string("Some kind of accept exception: ") + tx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
continue;
|
||||
} catch (string s) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
string errStr = string("Some kind of accept exception: ") + s;
|
||||
GlobalOutput(errStr.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the processor
|
||||
shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
|
||||
outputProtocol, client);
|
||||
|
||||
void* connectionContext = NULL;
|
||||
if (eventHandler_ != NULL) {
|
||||
connectionContext = eventHandler_->createContext(inputProtocol, outputProtocol);
|
||||
}
|
||||
try {
|
||||
for (;;) {
|
||||
if (eventHandler_ != NULL) {
|
||||
eventHandler_->processContext(connectionContext, client);
|
||||
}
|
||||
if (!processor->process(inputProtocol, outputProtocol,
|
||||
connectionContext) ||
|
||||
// Peek ahead, is the remote side closed?
|
||||
!inputProtocol->getTransport()->peek()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (const TTransportException& ttx) {
|
||||
string errStr = string("TSimpleServer client died: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
} catch (const std::exception& x) {
|
||||
GlobalOutput.printf("TSimpleServer exception: %s: %s",
|
||||
typeid(x).name(), x.what());
|
||||
} catch (...) {
|
||||
GlobalOutput("TSimpleServer uncaught exception.");
|
||||
}
|
||||
if (eventHandler_ != NULL) {
|
||||
eventHandler_->deleteContext(connectionContext, inputProtocol, outputProtocol);
|
||||
}
|
||||
|
||||
try {
|
||||
inputTransport->close();
|
||||
} catch (const TTransportException& ttx) {
|
||||
string errStr = string("TSimpleServer input close failed: ")
|
||||
+ ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
try {
|
||||
outputTransport->close();
|
||||
} catch (const TTransportException& ttx) {
|
||||
string errStr = string("TSimpleServer output close failed: ")
|
||||
+ ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
try {
|
||||
client->close();
|
||||
} catch (const TTransportException& ttx) {
|
||||
string errStr = string("TSimpleServer client close failed: ")
|
||||
+ ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (stop_) {
|
||||
try {
|
||||
serverTransport_->close();
|
||||
} catch (TTransportException &ttx) {
|
||||
string errStr = string("TServerTransport failed on close: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
stop_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
}}} // apache::thrift::server
|
|
@ -20,8 +20,8 @@
|
|||
#ifndef _THRIFT_SERVER_TSIMPLESERVER_H_
|
||||
#define _THRIFT_SERVER_TSIMPLESERVER_H_ 1
|
||||
|
||||
#include "server/TServer.h"
|
||||
#include "transport/TServerTransport.h"
|
||||
#include <thrift/server/TServer.h>
|
||||
#include <thrift/transport/TServerTransport.h>
|
||||
|
||||
namespace apache { namespace thrift { namespace server {
|
||||
|
||||
|
@ -34,19 +34,50 @@ namespace apache { namespace thrift { namespace server {
|
|||
*/
|
||||
class TSimpleServer : public TServer {
|
||||
public:
|
||||
TSimpleServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport,
|
||||
boost::shared_ptr<TTransportFactory> transportFactory,
|
||||
boost::shared_ptr<TProtocolFactory> protocolFactory) :
|
||||
template<typename ProcessorFactory>
|
||||
TSimpleServer(
|
||||
const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
|
||||
TServer(processorFactory, serverTransport, transportFactory,
|
||||
protocolFactory),
|
||||
stop_(false) {}
|
||||
|
||||
template<typename Processor>
|
||||
TSimpleServer(
|
||||
const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
|
||||
TServer(processor, serverTransport, transportFactory, protocolFactory),
|
||||
stop_(false) {}
|
||||
|
||||
TSimpleServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport,
|
||||
boost::shared_ptr<TTransportFactory> inputTransportFactory,
|
||||
boost::shared_ptr<TTransportFactory> outputTransportFactory,
|
||||
boost::shared_ptr<TProtocolFactory> inputProtocolFactory,
|
||||
boost::shared_ptr<TProtocolFactory> outputProtocolFactory):
|
||||
template<typename ProcessorFactory>
|
||||
TSimpleServer(
|
||||
const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
|
||||
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
|
||||
TServer(processorFactory, serverTransport,
|
||||
inputTransportFactory, outputTransportFactory,
|
||||
inputProtocolFactory, outputProtocolFactory),
|
||||
stop_(false) {}
|
||||
|
||||
template<typename Processor>
|
||||
TSimpleServer(
|
||||
const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
|
||||
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
|
||||
TServer(processor, serverTransport,
|
||||
inputTransportFactory, outputTransportFactory,
|
||||
inputProtocolFactory, outputProtocolFactory),
|
||||
|
|
205
nativeLib/org.apache.thrift/include/server/TThreadPoolServer.cpp
Normal file
205
nativeLib/org.apache.thrift/include/server/TThreadPoolServer.cpp
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <thrift/server/TThreadPoolServer.h>
|
||||
#include <thrift/transport/TTransportException.h>
|
||||
#include <thrift/concurrency/Thread.h>
|
||||
#include <thrift/concurrency/ThreadManager.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace apache { namespace thrift { namespace server {
|
||||
|
||||
using boost::shared_ptr;
|
||||
using namespace std;
|
||||
using namespace apache::thrift;
|
||||
using namespace apache::thrift::concurrency;
|
||||
using namespace apache::thrift::protocol;
|
||||
using namespace apache::thrift::transport;
|
||||
|
||||
class TThreadPoolServer::Task : public Runnable {
|
||||
|
||||
public:
|
||||
|
||||
Task(TThreadPoolServer &server,
|
||||
shared_ptr<TProcessor> processor,
|
||||
shared_ptr<TProtocol> input,
|
||||
shared_ptr<TProtocol> output,
|
||||
shared_ptr<TTransport> transport) :
|
||||
server_(server),
|
||||
processor_(processor),
|
||||
input_(input),
|
||||
output_(output),
|
||||
transport_(transport) {
|
||||
}
|
||||
|
||||
~Task() {}
|
||||
|
||||
void run() {
|
||||
boost::shared_ptr<TServerEventHandler> eventHandler =
|
||||
server_.getEventHandler();
|
||||
void* connectionContext = NULL;
|
||||
if (eventHandler != NULL) {
|
||||
connectionContext = eventHandler->createContext(input_, output_);
|
||||
}
|
||||
try {
|
||||
for (;;) {
|
||||
if (eventHandler != NULL) {
|
||||
eventHandler->processContext(connectionContext, transport_);
|
||||
}
|
||||
if (!processor_->process(input_, output_, connectionContext) ||
|
||||
!input_->getTransport()->peek()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (const TTransportException&) {
|
||||
// This is reasonably expected, client didn't send a full request so just
|
||||
// ignore him
|
||||
// string errStr = string("TThreadPoolServer client died: ") + ttx.what();
|
||||
// GlobalOutput(errStr.c_str());
|
||||
} catch (const std::exception& x) {
|
||||
GlobalOutput.printf("TThreadPoolServer exception %s: %s",
|
||||
typeid(x).name(), x.what());
|
||||
} catch (...) {
|
||||
GlobalOutput("TThreadPoolServer, unexpected exception in "
|
||||
"TThreadPoolServer::Task::run()");
|
||||
}
|
||||
|
||||
if (eventHandler != NULL) {
|
||||
eventHandler->deleteContext(connectionContext, input_, output_);
|
||||
}
|
||||
|
||||
try {
|
||||
input_->getTransport()->close();
|
||||
} catch (TTransportException& ttx) {
|
||||
string errStr = string("TThreadPoolServer input close failed: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
try {
|
||||
output_->getTransport()->close();
|
||||
} catch (TTransportException& ttx) {
|
||||
string errStr = string("TThreadPoolServer output close failed: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
TServer& server_;
|
||||
shared_ptr<TProcessor> processor_;
|
||||
shared_ptr<TProtocol> input_;
|
||||
shared_ptr<TProtocol> output_;
|
||||
shared_ptr<TTransport> transport_;
|
||||
};
|
||||
|
||||
TThreadPoolServer::~TThreadPoolServer() {}
|
||||
|
||||
void TThreadPoolServer::serve() {
|
||||
shared_ptr<TTransport> client;
|
||||
shared_ptr<TTransport> inputTransport;
|
||||
shared_ptr<TTransport> outputTransport;
|
||||
shared_ptr<TProtocol> inputProtocol;
|
||||
shared_ptr<TProtocol> outputProtocol;
|
||||
|
||||
// Start the server listening
|
||||
serverTransport_->listen();
|
||||
|
||||
// Run the preServe event
|
||||
if (eventHandler_ != NULL) {
|
||||
eventHandler_->preServe();
|
||||
}
|
||||
|
||||
while (!stop_) {
|
||||
try {
|
||||
client.reset();
|
||||
inputTransport.reset();
|
||||
outputTransport.reset();
|
||||
inputProtocol.reset();
|
||||
outputProtocol.reset();
|
||||
|
||||
// Fetch client from server
|
||||
client = serverTransport_->accept();
|
||||
|
||||
// Make IO transports
|
||||
inputTransport = inputTransportFactory_->getTransport(client);
|
||||
outputTransport = outputTransportFactory_->getTransport(client);
|
||||
inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
|
||||
outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
|
||||
|
||||
shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
|
||||
outputProtocol, client);
|
||||
|
||||
// Add to threadmanager pool
|
||||
shared_ptr<TThreadPoolServer::Task> task(new TThreadPoolServer::Task(
|
||||
*this, processor, inputProtocol, outputProtocol, client));
|
||||
threadManager_->add(task, timeout_);
|
||||
|
||||
} catch (TTransportException& ttx) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED) {
|
||||
string errStr = string("TThreadPoolServer: TServerTransport died on accept: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
continue;
|
||||
} catch (TException& tx) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
string errStr = string("TThreadPoolServer: Caught TException: ") + tx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
continue;
|
||||
} catch (string s) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
string errStr = "TThreadPoolServer: Unknown exception: " + s;
|
||||
GlobalOutput(errStr.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If stopped manually, join the existing threads
|
||||
if (stop_) {
|
||||
try {
|
||||
serverTransport_->close();
|
||||
threadManager_->join();
|
||||
} catch (TException &tx) {
|
||||
string errStr = string("TThreadPoolServer: Exception shutting down: ") + tx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
stop_ = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int64_t TThreadPoolServer::getTimeout() const {
|
||||
return timeout_;
|
||||
}
|
||||
|
||||
void TThreadPoolServer::setTimeout(int64_t value) {
|
||||
timeout_ = value;
|
||||
}
|
||||
|
||||
}}} // apache::thrift::server
|
|
@ -20,9 +20,9 @@
|
|||
#ifndef _THRIFT_SERVER_TTHREADPOOLSERVER_H_
|
||||
#define _THRIFT_SERVER_TTHREADPOOLSERVER_H_ 1
|
||||
|
||||
#include <concurrency/ThreadManager.h>
|
||||
#include <server/TServer.h>
|
||||
#include <transport/TServerTransport.h>
|
||||
#include <thrift/concurrency/ThreadManager.h>
|
||||
#include <thrift/server/TServer.h>
|
||||
#include <thrift/transport/TServerTransport.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
@ -37,19 +37,66 @@ class TThreadPoolServer : public TServer {
|
|||
public:
|
||||
class Task;
|
||||
|
||||
TThreadPoolServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport,
|
||||
boost::shared_ptr<TTransportFactory> transportFactory,
|
||||
boost::shared_ptr<TProtocolFactory> protocolFactory,
|
||||
boost::shared_ptr<ThreadManager> threadManager);
|
||||
template<typename ProcessorFactory>
|
||||
TThreadPoolServer(
|
||||
const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
const boost::shared_ptr<ThreadManager>& threadManager,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
|
||||
TServer(processorFactory, serverTransport, transportFactory,
|
||||
protocolFactory),
|
||||
threadManager_(threadManager),
|
||||
stop_(false),
|
||||
timeout_(0) {}
|
||||
|
||||
TThreadPoolServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport,
|
||||
boost::shared_ptr<TTransportFactory> inputTransportFactory,
|
||||
boost::shared_ptr<TTransportFactory> outputTransportFactory,
|
||||
boost::shared_ptr<TProtocolFactory> inputProtocolFactory,
|
||||
boost::shared_ptr<TProtocolFactory> outputProtocolFactory,
|
||||
boost::shared_ptr<ThreadManager> threadManager);
|
||||
template<typename Processor>
|
||||
TThreadPoolServer(
|
||||
const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
const boost::shared_ptr<ThreadManager>& threadManager,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
|
||||
TServer(processor, serverTransport, transportFactory, protocolFactory),
|
||||
threadManager_(threadManager),
|
||||
stop_(false),
|
||||
timeout_(0) {}
|
||||
|
||||
template<typename ProcessorFactory>
|
||||
TThreadPoolServer(
|
||||
const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
|
||||
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
|
||||
const boost::shared_ptr<ThreadManager>& threadManager,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
|
||||
TServer(processorFactory, serverTransport,
|
||||
inputTransportFactory, outputTransportFactory,
|
||||
inputProtocolFactory, outputProtocolFactory),
|
||||
threadManager_(threadManager),
|
||||
stop_(false),
|
||||
timeout_(0) {}
|
||||
|
||||
template<typename Processor>
|
||||
TThreadPoolServer(
|
||||
const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
|
||||
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
|
||||
const boost::shared_ptr<ThreadManager>& threadManager,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
|
||||
TServer(processor, serverTransport,
|
||||
inputTransportFactory, outputTransportFactory,
|
||||
inputProtocolFactory, outputProtocolFactory),
|
||||
threadManager_(threadManager),
|
||||
stop_(false),
|
||||
timeout_(0) {}
|
||||
|
||||
virtual ~TThreadPoolServer();
|
||||
|
||||
|
|
241
nativeLib/org.apache.thrift/include/server/TThreadedServer.cpp
Normal file
241
nativeLib/org.apache.thrift/include/server/TThreadedServer.cpp
Normal file
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <thrift/server/TThreadedServer.h>
|
||||
#include <thrift/transport/TTransportException.h>
|
||||
#include <thrift/concurrency/PlatformThreadFactory.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace apache { namespace thrift { namespace server {
|
||||
|
||||
using boost::shared_ptr;
|
||||
using namespace std;
|
||||
using namespace apache::thrift;
|
||||
using namespace apache::thrift::protocol;
|
||||
using namespace apache::thrift::transport;
|
||||
using namespace apache::thrift::concurrency;
|
||||
|
||||
class TThreadedServer::Task: public Runnable {
|
||||
|
||||
public:
|
||||
|
||||
Task(TThreadedServer& server,
|
||||
shared_ptr<TProcessor> processor,
|
||||
shared_ptr<TProtocol> input,
|
||||
shared_ptr<TProtocol> output,
|
||||
shared_ptr<TTransport> transport) :
|
||||
server_(server),
|
||||
processor_(processor),
|
||||
input_(input),
|
||||
output_(output),
|
||||
transport_(transport) {
|
||||
}
|
||||
|
||||
~Task() {}
|
||||
|
||||
void run() {
|
||||
boost::shared_ptr<TServerEventHandler> eventHandler =
|
||||
server_.getEventHandler();
|
||||
void* connectionContext = NULL;
|
||||
if (eventHandler != NULL) {
|
||||
connectionContext = eventHandler->createContext(input_, output_);
|
||||
}
|
||||
try {
|
||||
for (;;) {
|
||||
if (eventHandler != NULL) {
|
||||
eventHandler->processContext(connectionContext, transport_);
|
||||
}
|
||||
if (!processor_->process(input_, output_, connectionContext) ||
|
||||
!input_->getTransport()->peek()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (const TTransportException& ttx) {
|
||||
if (ttx.getType() != TTransportException::END_OF_FILE) {
|
||||
string errStr = string("TThreadedServer client died: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
} catch (const std::exception &x) {
|
||||
GlobalOutput.printf("TThreadedServer exception: %s: %s",
|
||||
typeid(x).name(), x.what());
|
||||
} catch (...) {
|
||||
GlobalOutput("TThreadedServer uncaught exception.");
|
||||
}
|
||||
if (eventHandler != NULL) {
|
||||
eventHandler->deleteContext(connectionContext, input_, output_);
|
||||
}
|
||||
|
||||
try {
|
||||
input_->getTransport()->close();
|
||||
} catch (TTransportException& ttx) {
|
||||
string errStr = string("TThreadedServer input close failed: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
try {
|
||||
output_->getTransport()->close();
|
||||
} catch (TTransportException& ttx) {
|
||||
string errStr = string("TThreadedServer output close failed: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
|
||||
// Remove this task from parent bookkeeping
|
||||
{
|
||||
Synchronized s(server_.tasksMonitor_);
|
||||
server_.tasks_.erase(this);
|
||||
if (server_.tasks_.empty()) {
|
||||
server_.tasksMonitor_.notify();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
TThreadedServer& server_;
|
||||
friend class TThreadedServer;
|
||||
|
||||
shared_ptr<TProcessor> processor_;
|
||||
shared_ptr<TProtocol> input_;
|
||||
shared_ptr<TProtocol> output_;
|
||||
shared_ptr<TTransport> transport_;
|
||||
};
|
||||
|
||||
void TThreadedServer::init() {
|
||||
stop_ = false;
|
||||
|
||||
if (!threadFactory_) {
|
||||
threadFactory_.reset(new PlatformThreadFactory);
|
||||
}
|
||||
}
|
||||
|
||||
TThreadedServer::~TThreadedServer() {}
|
||||
|
||||
void TThreadedServer::serve() {
|
||||
|
||||
shared_ptr<TTransport> client;
|
||||
shared_ptr<TTransport> inputTransport;
|
||||
shared_ptr<TTransport> outputTransport;
|
||||
shared_ptr<TProtocol> inputProtocol;
|
||||
shared_ptr<TProtocol> outputProtocol;
|
||||
|
||||
// Start the server listening
|
||||
serverTransport_->listen();
|
||||
|
||||
// Run the preServe event
|
||||
if (eventHandler_ != NULL) {
|
||||
eventHandler_->preServe();
|
||||
}
|
||||
|
||||
while (!stop_) {
|
||||
try {
|
||||
client.reset();
|
||||
inputTransport.reset();
|
||||
outputTransport.reset();
|
||||
inputProtocol.reset();
|
||||
outputProtocol.reset();
|
||||
|
||||
// Fetch client from server
|
||||
client = serverTransport_->accept();
|
||||
|
||||
// Make IO transports
|
||||
inputTransport = inputTransportFactory_->getTransport(client);
|
||||
outputTransport = outputTransportFactory_->getTransport(client);
|
||||
inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
|
||||
outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
|
||||
|
||||
shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
|
||||
outputProtocol, client);
|
||||
|
||||
TThreadedServer::Task* task = new TThreadedServer::Task(*this,
|
||||
processor,
|
||||
inputProtocol,
|
||||
outputProtocol,
|
||||
client);
|
||||
|
||||
// Create a task
|
||||
shared_ptr<Runnable> runnable =
|
||||
shared_ptr<Runnable>(task);
|
||||
|
||||
// Create a thread for this task
|
||||
shared_ptr<Thread> thread =
|
||||
shared_ptr<Thread>(threadFactory_->newThread(runnable));
|
||||
|
||||
// Insert thread into the set of threads
|
||||
{
|
||||
Synchronized s(tasksMonitor_);
|
||||
tasks_.insert(task);
|
||||
}
|
||||
|
||||
// Start the thread!
|
||||
thread->start();
|
||||
|
||||
} catch (TTransportException& ttx) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED) {
|
||||
string errStr = string("TThreadedServer: TServerTransport died on accept: ") + ttx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
continue;
|
||||
} catch (TException& tx) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
string errStr = string("TThreadedServer: Caught TException: ") + tx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
continue;
|
||||
} catch (string s) {
|
||||
if (inputTransport != NULL) { inputTransport->close(); }
|
||||
if (outputTransport != NULL) { outputTransport->close(); }
|
||||
if (client != NULL) { client->close(); }
|
||||
string errStr = "TThreadedServer: Unknown exception: " + s;
|
||||
GlobalOutput(errStr.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If stopped manually, make sure to close server transport
|
||||
if (stop_) {
|
||||
try {
|
||||
serverTransport_->close();
|
||||
} catch (TException &tx) {
|
||||
string errStr = string("TThreadedServer: Exception shutting down: ") + tx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
try {
|
||||
Synchronized s(tasksMonitor_);
|
||||
while (!tasks_.empty()) {
|
||||
tasksMonitor_.wait();
|
||||
}
|
||||
} catch (TException &tx) {
|
||||
string errStr = string("TThreadedServer: Exception joining workers: ") + tx.what();
|
||||
GlobalOutput(errStr.c_str());
|
||||
}
|
||||
stop_ = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}} // apache::thrift::server
|
|
@ -20,10 +20,10 @@
|
|||
#ifndef _THRIFT_SERVER_TTHREADEDSERVER_H_
|
||||
#define _THRIFT_SERVER_TTHREADEDSERVER_H_ 1
|
||||
|
||||
#include <server/TServer.h>
|
||||
#include <transport/TServerTransport.h>
|
||||
#include <concurrency/Monitor.h>
|
||||
#include <concurrency/Thread.h>
|
||||
#include <thrift/server/TServer.h>
|
||||
#include <thrift/transport/TServerTransport.h>
|
||||
#include <thrift/concurrency/Monitor.h>
|
||||
#include <thrift/concurrency/Thread.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
@ -40,16 +40,35 @@ class TThreadedServer : public TServer {
|
|||
public:
|
||||
class Task;
|
||||
|
||||
TThreadedServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport,
|
||||
boost::shared_ptr<TTransportFactory> transportFactory,
|
||||
boost::shared_ptr<TProtocolFactory> protocolFactory);
|
||||
template<typename ProcessorFactory>
|
||||
TThreadedServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory));
|
||||
|
||||
TThreadedServer(boost::shared_ptr<TProcessor> processor,
|
||||
boost::shared_ptr<TServerTransport> serverTransport,
|
||||
boost::shared_ptr<TTransportFactory> transportFactory,
|
||||
boost::shared_ptr<TProtocolFactory> protocolFactory,
|
||||
boost::shared_ptr<ThreadFactory> threadFactory);
|
||||
template<typename ProcessorFactory>
|
||||
TThreadedServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
const boost::shared_ptr<ThreadFactory>& threadFactory,
|
||||
THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory));
|
||||
|
||||
template<typename Processor>
|
||||
TThreadedServer(const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor));
|
||||
|
||||
template<typename Processor>
|
||||
TThreadedServer(const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
const boost::shared_ptr<ThreadFactory>& threadFactory,
|
||||
THRIFT_OVERLOAD_IF(Processor, TProcessor));
|
||||
|
||||
virtual ~TThreadedServer();
|
||||
|
||||
|
@ -61,6 +80,8 @@ class TThreadedServer : public TServer {
|
|||
}
|
||||
|
||||
protected:
|
||||
void init();
|
||||
|
||||
boost::shared_ptr<ThreadFactory> threadFactory_;
|
||||
volatile bool stop_;
|
||||
|
||||
|
@ -69,6 +90,56 @@ class TThreadedServer : public TServer {
|
|||
|
||||
};
|
||||
|
||||
template<typename ProcessorFactory>
|
||||
TThreadedServer::TThreadedServer(
|
||||
const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
THRIFT_OVERLOAD_IF_DEFN(ProcessorFactory, TProcessorFactory)) :
|
||||
TServer(processorFactory, serverTransport, transportFactory,
|
||||
protocolFactory) {
|
||||
init();
|
||||
}
|
||||
|
||||
template<typename ProcessorFactory>
|
||||
TThreadedServer::TThreadedServer(
|
||||
const boost::shared_ptr<ProcessorFactory>& processorFactory,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
const boost::shared_ptr<ThreadFactory>& threadFactory,
|
||||
THRIFT_OVERLOAD_IF_DEFN(ProcessorFactory, TProcessorFactory)) :
|
||||
TServer(processorFactory, serverTransport, transportFactory,
|
||||
protocolFactory),
|
||||
threadFactory_(threadFactory) {
|
||||
init();
|
||||
}
|
||||
|
||||
template<typename Processor>
|
||||
TThreadedServer::TThreadedServer(
|
||||
const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
THRIFT_OVERLOAD_IF_DEFN(Processor, TProcessor)) :
|
||||
TServer(processor, serverTransport, transportFactory, protocolFactory) {
|
||||
init();
|
||||
}
|
||||
|
||||
template<typename Processor>
|
||||
TThreadedServer::TThreadedServer(
|
||||
const boost::shared_ptr<Processor>& processor,
|
||||
const boost::shared_ptr<TServerTransport>& serverTransport,
|
||||
const boost::shared_ptr<TTransportFactory>& transportFactory,
|
||||
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
|
||||
const boost::shared_ptr<ThreadFactory>& threadFactory,
|
||||
THRIFT_OVERLOAD_IF_DEFN(Processor, TProcessor)) :
|
||||
TServer(processor, serverTransport, transportFactory, protocolFactory),
|
||||
threadFactory_(threadFactory) {
|
||||
init();
|
||||
}
|
||||
|
||||
}}} // apache::thrift::server
|
||||
|
||||
#endif // #ifndef _THRIFT_SERVER_TTHREADEDSERVER_H_
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue