Sounds good. Feel free to submit the patch. Let's just consider this an
undocumented feature of Thrift, rather than a part of the interface we're
committed to keep supporting.
--David
On 09/08/2010 09:22 AM, Rush Manbert wrote:
> Once I really had to implement something, it turned out that with about 10
> lines of code in Thrift.h and Thrift.cpp I could avoid changing any
> occurrences of GlobalOutput. That's a small enough change that I think we can
> manage it in our local codebase.
>
> Believe me, I would avoid this if I could. But I can't. At this point I have
> picked apart all of the Thrift C++ code, and I know how I implemented the
> local sockets, so I'm confident that I can know the data is initialized
> before I use it. And once I put the visceral reaction aside and thought about
> it some more, it's not like we're doing this during system startup, it's just
> at a point in the client application's lifetime where you need to deal
> correctly with indeterminate initialization order. Something we avoid like
> the plague, but it doesn't quite require rocket science. Of course, maybe I
> just need to convince myself that it will be okay, since I'm stuck with it.
> :-)
>
> If GlobalOutput gets replaced with a real logging implementation, then we may
> have issues. But the prerelease version I'm running on has all the features
> we need to run our apps, so I've got choices.
>
> Thank you for your thoughts,
> Rush
>
> On Sep 7, 2010, at 11:05 PM, Bruce Lowekamp wrote:
>
>>
>> I suppose that in the future, something like that could be extended so that
>> a simple static-time logger that logs to stderr could be replaced with a
>> non-static logger once the system is up, but that seems like a lot of
>> complexity for something that I think isn't a good idea to do in the first
>> place.
>>
>> Bruce
>>
>>
>> On Sep 3, 2010, at 7:29 PM, David Reiss wrote:
>>
>>> I'd be fine with this change, but I also think that it would be a good idea
>>> for Thrift to switch to a real logging library at some point. When that
>>> time
>>> comes, I don't want the choice to be limited to libraries that can safely be
>>> used during static initialization. Seriously, "don't do that."
>>>
>>> --David
>>>
>>> On 09/03/2010 04:46 PM, Rush Manbert wrote:
>>>> I'm hoping the hard core C++ guys will think about this a little and maybe
>>>> have some suggestions. It's an esoteric enough problem that you might find
>>>> it interesting. :-)
>>>>
>>>> For complicated reasons, we sometimes end up trying to open a Thrift
>>>> socket connection to a local server process during client-side static init
>>>> time. I know that the simple answer would be "don't do that", but that's
>>>> really not possible.
>>>>
>>>> This has worked just fine as long as the server process is running. If it
>>>> is not running, however, the client app has a high probability of crashing
>>>> when the socket connection attempt fails. This is because when such an
>>>> error occurs, the output is handled by calling GlobalOutput.perror, like
>>>> so:
>>>>
>>>> GlobalOutput.perror("TSocket::open() socket() " + getSocketInfo(),
>>>> errno_copy);
>>>>
>>>> The problem is that GlobalOutput is a global object that is constructed at
>>>> static init time. Since we can't control the order in which global objects
>>>> are initialized, we may try to communicate before GlobalOutput has been
>>>> constructed. Thus the crash. (The situation is analogous to a global
>>>> object trying to connect to the server in the object's constructor.
>>>> Depending on the order of static init execution, GlobalOutput may or may
>>>> not have been constructed when the connection attempt is made.)
>>>>
>>>> The GlobalOutput object is instantiated in Thrift.cpp with this line of
>>>> code:
>>>>
>>>> TOutput GlobalOutput;
>>>>
>>>> The easy way to fix this problem is to wrap the global object in a
>>>> "construct on first use" function
>>>> (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.15) like this:
>>>>
>>>> TOutput &GlobalOutput (void)
>>>> {
>>>> static TOutput GlobalOutput;
>>>> return GlobalOutput;
>>>> }
>>>>
>>>> which guarantees that it gets constructed the first time GlobalOuput() is
>>>> called, but then I will need to change every existing reference to
>>>> GlobalOutput to a function call to GlobalOutput(). So, for instance, the
>>>> call to perror that I pasted above would change to:
>>>>
>>>> GlobalOutput().perror("TSocket::open() socket() " + getSocketInfo(),
>>>> errno_copy);
>>>>
>>>>
>>>> As usual, I have a list of questions (but it's short):
>>>>
>>>> 1) Can anyone think of another way around this problem?
>>>>
>>>> 2) Would the C++ library developers be at all receptive to taking the
>>>> change I have outlined (GlobalOutput -> GlobalOutput()) into the trunk? On
>>>> one hand, it adds a function call. On the other hand the operation in
>>>> progress is formatted output, so one extra function call to get the
>>>> reference probably doesn't matter. On yet the other hand, the change would
>>>> have to extend to the server side code as well, and probably you guys
>>>> running large server side operations worry about error performance more
>>>> that I worry about client side performance in the same situation.
>>>>
>>>> TIA,
>>>> Rush
>