I have simple messages:
message SmallValue {
int32 val = 1;
}
message Value {
int32 val1 = 1;
int32 val2 = 2;
SmallValue val3 = 3;
}
message SendMessage {
int32 id = 1;
oneof message {
Value value= 2;
}
My piece of code:
// create new pointer for smallValue
SmallValue* smallValue = new SmallValue();
smallValue->set_val3(3);
// create new object value and set_allocated_val3
Value value;
value.set_val1(1);
value.set_val2(2);
value.set_allocated_val3(smallValue);
// create new object message and set_allocated_value
SendMessage message;
message.set_id(0);
message.set_allocated_value(&value);
// after some work, release value from message
message.release_value();
And my questions are:
1. After calling message.release_value() is it OK not to call delete &value; as I didn't create new pointer?
2. Will memory of smallValue will be deleted automatically along with value as I didn't call value.release_smallValue();?
// I'm a newbie to C++ as well as protobuf. Please do tell if something odd about my code.
Thanks!
It is usually best to avoid using the set_allocated_* and release_* methods; those provide advanced memory-management features that you should not need unless you are really trying to optimize some performance-critical code.
You could rewrite your code like this to avoid having to worry about memory management as much:
SendMessage message;
message.set_id(0);
Value* value = message.mutable_value();
value->set_val1(1);
value->set_val2(2);
value->mutable_val3()->set_val(3);
Related
I can't find a grpc example showing how to use the ClientAsyncReaderWriter (is there one?). I tried something on my own, but am having trouble with the reference counts. My question comes from tracing through the code.
struct grpc_call has a member of type gpr_refcount called ext_ref. The ClientContext C++ object wraps the grpc_call, and holds onto it in a member grpc_call *call_;. Only when ext_ref is 0, can this grpc_call pointer be deleted.
When I use grpc synchronously with ClientReader:
In its implementation it uses CreateCall() and PerformOps() to add to ext_ref (ext_ref == 2).
Then I use Pluck() which subtracts from ext_ref so that (ext_ref == 1).
The last use ~ClientContext() subtracts from ext_ref, so that ext_ref == 0 and deletes the call
But when I use grpc asynchronously with ClientAsyncReaderWriter:
First use asyncXXX(), this API use CreateCall() and register Write() (ext_ref == 2).
Then it uses AsyncNext() to get tag...which must use a write or read operator.
So ext_ref > 1 forever, unless got_event you don't handle.
I'm calling it like this:
struct Notice
{
std::unique_ptr<
grpc::ClientAsyncReaderWriter<ObserveNoticRequest, EventNotice>
> _rw;
ClientContext _context;
EventNotice _rsp;
}
Register Thread
CompletionQueue *cq = new CompletionQueue;
Notice *notice = new Notice;
notice->rw = stub->AsyncobserverNotice(&context, cq, notice);
// here context.call_.ext_ref is 2
Get CompletionQueue Event Thread
void *tag = NULL;
bool ok = false;
CompletionQueue::NextStatus got = CompletionQueue::NextStatus::TIMEOUT;
gpr_timespec deadline;
deadline.clock_type = GPR_TIMESPAN;
deadline.tv_sec = 0;
deadline.tv_nsec = 10000000;
got = cq->AsyncNext<gpr_timespec>(&tag, &ok, deadline);
if (GOT_EVENT == got) {
if (tag != NULL) {
Notice *notice = (Notice *)tag;
notice->_rw->Read(&_rsp, notice);
// here context.call_.ext_ref is 2.
// now I want to stop this CompletionQueue.
delete notice;
// use ~ClientContext(), ext_ref change to 1
// but only ext_ref == 0, call_ be deleted
}
}
Take a look at this file, client_async.cc, for good use of the ClientAsyncReaderWriter. If you still have confusion, please create a very clean reproduction of the issue, and we will look into it further.
To reuse protobuf messages, I firstly allocate it(msg_test,msg_proto), and then send it in an loop(for every loop do something like clear,set,send).
protobuf syntax = "proto3";
Call:
int i=0;
while(true){
SendTestImprove(i++);
usleep(1000*1000);
}
Function:
int SendTestImprove(int count)
{
msg_test->Clear();
msg_test->set_count(count);
msg_proto->Clear();
msg_proto->set_allocated_count(msg_test);
msg_proto->set_tick_count(GetTickCount());
zmq_msg_t zmsg;
int size = msg_proto->ByteSize();
int rc = zmq_msg_init_size(&zmsg,size);
if(rc==0){
try
{
rc = msg_proto->SerializeToArray(zmq_msg_data(&zmsg),size)?0:-1;
}
catch (google::protobuf::FatalException fe)
{
LOGFMTE("PbToZmq error: %s",fe.message().c_str());
}
}
int zsize = zmq_msg_size(&zmsg);
rc = zmq_msg_send(&zmsg,m_pub,0);
zmq_msg_close(&zmsg);
LOGFMTD("zmq_msg_send,size=%d,zsize=%d",rc,zsize);
return 0;
}
The error occurred when i=1, at the line :
rc = msg_proto->SerializeToArray(zmq_msg_data(&zmsg),size)?0:-1;
error info is like:
stopped:segmentation fault,at
InternalWriteMessageNoVirtualToArray
,InternalSerializeWithCachedSizesToArray
Can anyone help?
The likely problem is that you're assigning ownership of msg_test to msg_proto in each iteration of the loop, by calling msg_proto->set_allocated_count(msg_test). The first time you do that it's fine, but then the next time through the loop when you call set_allocated_count() a second time, the proto will delete msg_test and reassign the now dangling pointer. The simplest solution is to avoid calling set_allocated_count() and instead just assign a copy of msg_test, like this:
*msg_proto->mutable_count() = msg_test;
I'm writing a tool in c++ using RTI DDS 5.2 that needs to detect when DataWriters are deleted and know the type_name of the related data. I'm using code similar to this and this.
I'm using a DDSWaitSet and it is getting triggered when a DataWriter is deleted with delete_datawriter but the SampleInfo indicates that the data is not valid and sure enough, the data sample type_name is empty.
Is there a way to delete a DataWriter in such a was as to cause the built in topic subscription to get the type_name? Or is there a QOS setting I can set to fix this behavior?
Found a workaround for this problem. I still don't know how to make it so the data sample is valid when a DataWriter goes away, but the SampleInfo does have the field instance_state which uniquely identifies the writer. The solution is to keep track of type_names when the data is valid and just look it up when it's not. Here is the gist of the code I am using to solve the issue:
struct cmp_instance_handle {
bool operator()(const DDS_InstanceHandle_t& a, const DDS_InstanceHandle_t& b) const {
return !DDS_InstanceHandle_equals(&a, &b);
}
};
void wait_for_data_writer_samples()
{
ConditionSeq cs;
DDSWaitSet* ws = new DDSWaitSet();
StatusCondition* condition = _publication_dr->get_statuscondition();
DDS_Duration_t timeout = {DDS_DURATION_INFINITE_SEC, DDS_DURATION_INFINITE_NSEC};
std::map<DDS_InstanceHandle_t, std::string, cmp_instance_handle> instance_handle_map;
ws->attach_condition(condition);
condition->set_enabled_statuses(DDS_STATUS_MASK_ALL);
while(true) {
ws->wait(cs, timeout);
PublicationBuiltinTopicDataSeq data_seq;
SampleInfoSeq info_seq;
_publication_dr->take(
data_seq,
info_seq,
DDS_LENGTH_UNLIMITED,
ANY_SAMPLE_STATE,
ANY_VIEW_STATE,
ANY_INSTANCE_STATE
);
int len = data_seq.length();
for(int i = 0; i < len; ++i) {
DDS_InstanceHandle_t instance_handle = info_seq[i].instance_handle;
if(info_seq[i].valid_data) {
std::string type_name(data_seq[i].type_name);
// store the type_name in the map for future use
instance_handle_map[instance_handle] = type_name;
if(info_seq[i].instance_state == DDS_InstanceStateKind::DDS_ALIVE_INSTANCE_STATE) {
do_data_writer_alive_callback(type_name);
}
else {
// If the data is valid, but not DDS_ALIVE_INSTANCE_STATE, the DataWriter died *and* we can
// directly access the type_name so we can handle that case here
do_data_writer_dead_callback(type_name);
}
}
else {
// If the data is not valid then the DataWriter is definitely not alive but we can't directly access
// the type_name. Fortunately we can look it up in our map.
do_data_writer_dead_callback(instance_handle_map[instance_handle]);
// at this point the DataWriter is gone so we remove it from the map.
instance_handle_map.erase(instance_handle);
}
}
_publication_dr->return_loan(data_seq, info_seq);
}
}
I'm new to protobuf and I'm stuck with simple task: I need to iterate through fields of message and check it's type. If type is message I will do same recursively for this message.
For example, I have such messages:
package MyTool;
message Configuration {
required GloablSettings globalSettings = 1;
optional string option1 = 2;
optional int32 option2 = 3;
optional bool option3 = 4;
}
message GloablSettings {
required bool option1 = 1;
required bool option2 = 2;
required bool option3 = 3;
}
Now, to explicitly access a field value in C++ I can do this:
MyTool::Configuration config;
fstream input("config", ios::in | ios::binary);
config.ParseFromIstream(&input);
bool option1val = config.globalSettings().option1();
bool option2val = config.globalSettings().option2();
and so on. This approach is not convenient in case when have big amount of fields.
Can I do this with iteration and get field's name and type? I know there are descriptors of type and somewhat called reflection, but I didn't have success in my attempts.
Can some one give me example of code if it's possible?
Thanks!
This is old but maybe someone will benefit. Here is a method that prints the contents of a protobuf message:
void Example::printMessageContents(std::shared_ptr<google::protobuf::Message> m)
{
const Descriptor *desc = m->GetDescriptor();
const Reflection *refl = m->GetReflection();
int fieldCount= desc->field_count();
fprintf(stderr, "The fullname of the message is %s \n", desc->full_name().c_str());
for(int i=0;i<fieldCount;i++)
{
const FieldDescriptor *field = desc->field(i);
fprintf(stderr, "The name of the %i th element is %s and the type is %s \n",i,field->name().c_str(),field->type_name());
}
}
You can find in FieldDescriptor Enum Values the possible values you get from field->type. For example for the message type you would have to check if type is equal to FieldDescriptor::TYPE_MESSAGE.
This function prints all the "metadata" of the protobuf message. However you need to check separately for each value what the type is and then call the corresponding getter function using Reflection.
So using this condition we could extract the strings :
if(field->type() == FieldDescriptor::TYPE_STRING && !field->is_repeated())
{
std::string g= refl->GetString(*m, field);
fprintf(stderr, "The value is %s ",g.c_str());
}
However fields can be either repeated or not repeated and different methods are used for both field types. So a check is used here to assure that we are using the right method. For repeated fields we have for example this method for strings :
GetRepeatedString(const Message & message, const FieldDescriptor * field, int index)
So it takes the index of the repeated field into consideration.
In the case of FieldDescriptor of type Message, the function provided will only print the name of the message, we better print its contents too.
if(field->type()==FieldDescriptor::TYPE_MESSAGE)
{
if(!field->is_repeated())
{
const Message &mfield = refl->GetMessage(*m, field);
Message *mcopy = mfield.New();
mcopy->CopyFrom(mfield);
void *ptr = new std::shared_ptr<Message>(mcopy);
std::shared_ptr<Message> *m =
static_cast<std::shared_ptr<Message> *>(ptr);
printMessageContents(*m);
}
}
And finally if the field is repeated you will have to call the FieldSize method on the reflection and iterate all repeated fields.
Take a look at how the Protobuf library implements the TextFormat::Printer class, which uses descriptors and reflection to iterate over fields and convert them to text:
https://github.com/google/protobuf/blob/master/src/google/protobuf/text_format.cc#L1473
I am using CLucene for creating indexing and searching. The index files created are of more than 5 GB. I have Created the seperate dll for CLucene search.
DLL constructor contains the following code
lucene::index::IndexReader ptrIndexReader;
lucene::search::IndexSearcher searcher; these are defined in class decalaration/
ptrIndexReader = IndexReader::open(pDir.c_str(),false,NULL);
searcher = new IndexSearcher(ptrIndexReader);
I use one search function whose code is as follows
bool LuceneWrapper::SearchIndex(wstring somevalue)
{
lucene::analysis::KeywordAnalyzer fAnalyzer;
Document doc = NULL;
Hits hits = NULL;
Query f_objQuery = NULL;
NistRecord *f_objRecords = NULL;
bool flag = false;
try{
if (ptrIndexReader == NULL)
{
return NULL;
}
// Initialize IndexSearcher
wstring strQuery = _T("+somename:") + somevalue;
// Initialize Query Parser, with Keyword Analyzer
QueryParser *parser = new QueryParser( _T(""),&fAnalyzer);
// Parse Query string
f_objQuery = parser->parse(strQuery.c_str());
// Search Index directory
hits = searcher->search(f_objQuery);
//searcher.
int intHitCount = 0;
intHitCount = hits->length;
if(intHitCount > 0)
{
if(doc!=NULL)
delete [] doc;
flag = true;
}
//searcher.close();
}
catch(CLuceneError& objExp)
{
if(doc!=NULL)
delete doc;
return false;
}
if(hits!=NULL)
delete hits;
if(f_objQuery!=NULL)
delete f_objQuery;
return flag ;
}
I am searching very large number of values. according to the record count the main memory goes high and high and at on level it goes near to 2 GB and application crashes. Can anybody tell me what is wrong with this? Why is memory going so high and application crashing?
You never deallocate parser.
I can't see a reason to allocate it dynamically.
Why don't you just say
QueryParser parser( _T(""), &fAnalyzer);
f_objQuery = parser.parse(strQuery.c_str());
You also need to make sure that you delete both f_objQuery and hits in the event of an exception.
std::unique_ptr can help you here, if you have access to it.
(And you don't have to test for NULL so much - it's OK to delete a null pointer.)