The specification states states a "Span becomes non-recording by being ended". The specification reiterates this in the IsRecording section by saying "[a]fter a Span is ended, it usually becomes non-recording and thus IsRecording SHOULD consequently return false for ended Spans." This means that the End and IsRecorded must share some state about the ended nature of a Span.
How this shared state is manage in implementations as it can lead to a race condition if it is accessed simultaneously. To specify how this should be handled the specification state that "[a]ll methods of Span are safe to be called concurrently", but it also states the End method of a Span "MUST be non-blocking."
This seems to introduce a logical inconsistency. How can state be shared, be concurrent safe, and not block?
How can state be shared, be concurrent safe, and not block?
E.g, in case of Java I think both volatile fields and AtomicBoolean are thread-safe and considered non-blocking.
I don't think non-blocking was meant to imply "lock-free". It probably means that you should not synchronously do I/O e.g. to export the span. On the other hand, that's exactly what the built-in SimpleSpanProcessor does. IMHO we should remove that "non-blocking" requirement.
Most helpful comment
I don't think non-blocking was meant to imply "lock-free". It probably means that you should not synchronously do I/O e.g. to export the span. On the other hand, that's exactly what the built-in SimpleSpanProcessor does. IMHO we should remove that "non-blocking" requirement.