Issue #2215 upgrade thrift to version 0.9.0

Change-Id: I9cf910a75c25f1d97a711a9088c3b496ceb2be70

Former-commit-id: ab2e3f3e8910043b117887712258fc689f2e9445
This commit is contained in:
Nate Jensen 2013-07-23 12:21:31 -05:00
parent fa6a457cd0
commit 7b4938a999
182 changed files with 23494 additions and 2739 deletions

View file

@ -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"/>

View file

@ -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,

View file

@ -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

View file

@ -1,2 +0,0 @@
bin.includes = META-INF/,\
libthrift.jar

View file

@ -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,

View file

@ -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>

View 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>

View file

@ -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

View 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"

View file

@ -0,0 +1,2 @@
bin.includes = META-INF/,\
libthrift-0.9.0.jar

Binary file not shown.

View file

@ -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,

View file

@ -18,7 +18,7 @@
</license>
<plugin
id="com.facebook.thrift"
id="org.apache.thrift"
download-size="0"
install-size="0"
version="0.0.0"/>

View file

@ -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

View file

@ -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,

View file

@ -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());
}

View file

@ -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
*

View file

@ -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

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
/*

View file

@ -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);
}
}
}

View file

@ -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,

View file

@ -1,5 +0,0 @@
Version = 0.5.0
Origin
------
http://archive.apache.org/dist/incubator/thrift/0.5.0-incubating/

View file

@ -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

View file

@ -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() :

View 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_

View file

@ -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_

View file

@ -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_

View file

@ -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

View 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

View file

@ -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

View 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

View file

@ -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_

View 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

View 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_

View file

@ -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_

View 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_

View file

@ -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

View file

@ -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_

View file

@ -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

View file

@ -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_

View 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

View 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_

View 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

View file

@ -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

View file

@ -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

View file

@ -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_

View file

@ -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:

View file

@ -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.

View 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

View file

@ -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:

View 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

View file

@ -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)

View file

@ -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_

View file

@ -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

View file

@ -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() {};

View file

@ -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

View file

@ -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;

View 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

View file

@ -99,7 +99,7 @@ class TimerManager {
STOPPED
};
virtual const STATE state() const;
virtual STATE state() const;
private:
boost::shared_ptr<const ThreadFactory> threadFactory_;

View 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

View file

@ -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

View file

@ -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 */

View 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() {}
}}}

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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,
int32_t string_limit,
int32_t container_limit,
bool strict_read,
bool strict_write) :
TProtocol(trans),
TBinaryProtocolT(boost::shared_ptr<Transport_> trans,
int32_t string_limit,
int32_t container_limit,
bool strict_read,
bool strict_write) :
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,
const TMessageType messageType,
const int32_t seqid);
/*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,
const TType fieldType,
const int16_t fieldId);
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,
const TType valType,
const uint32_t size);
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,
TMessageType& messageType,
int32_t& seqid);
/*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,
TType& fieldType,
int16_t& fieldId);
inline uint32_t readFieldBegin(std::string& name,
TType& fieldType,
int16_t& fieldId);
uint32_t readFieldEnd();
inline uint32_t readFieldEnd();
uint32_t readMapBegin(TType& keyType,
TType& valType,
uint32_t& size);
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_

View 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_

View file

@ -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,
int32_t string_limit,
int32_t container_limit) :
TProtocol(trans),
TCompactProtocolT(boost::shared_ptr<Transport_> trans,
int32_t string_limit,
int32_t container_limit) :
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

View file

@ -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_

View 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

View file

@ -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,
const TMessageType messageType,
const int32_t seqid);
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 {

View 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

View file

@ -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,
const TMessageType messageType,
const int32_t seqid);
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,
const TType fieldType,
const int16_t fieldId);
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,
const TType valType,
const uint32_t size);
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);

File diff suppressed because it is too large Load diff

View file

@ -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 {

View file

@ -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_

View file

@ -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,
const TMessageType messageType,
const int32_t seqid) = 0;
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,
const TType fieldType,
const int16_t fieldId) = 0;
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,
const TType valType,
const uint32_t size) = 0;
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,
const uint32_t size) = 0;
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,
const uint32_t size) = 0;
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,
TMessageType& messageType,
int32_t& seqid) = 0;
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,
TType& fieldType,
int16_t& fieldId) = 0;
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,
TType& valType,
uint32_t& size) = 0;
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,
uint32_t& size) = 0;
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,
uint32_t& size) = 0;
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

View file

@ -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,44 +32,44 @@ 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,
TMessageType& messageType,
int32_t& seqid) {
uint32_t readMessageBegin(std::string& name,
TMessageType& messageType,
int32_t& seqid) {
uint32_t rv = source_->readMessageBegin(name, messageType, seqid);
sink_->writeMessageBegin(name, messageType, seqid);
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,
TType& fieldType,
int16_t& fieldId) {
uint32_t readFieldBegin(std::string& name,
TType& fieldType,
int16_t& fieldId) {
uint32_t rv = source_->readFieldBegin(name, fieldType, fieldId);
if (fieldType == T_STOP) {
sink_->writeFieldStop();
@ -80,98 +80,99 @@ 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,
TType& valType,
uint32_t& size) {
uint32_t readMapBegin(TType& keyType,
TType& valType,
uint32_t& size) {
uint32_t rv = source_->readMapBegin(keyType, valType, size);
sink_->writeMapBegin(keyType, valType, size);
return rv;
}
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;

View 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

View 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

View 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_

View 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

View 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_

View 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

File diff suppressed because it is too large Load diff

View 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

View file

@ -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_;

View 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

View file

@ -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),

View 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

View file

@ -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();

View 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

View file

@ -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