-
Notifications
You must be signed in to change notification settings - Fork 899
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce ObjectStore methods that take Session data #7135
Comments
I wonder if instead of altering the ObjectStore trait, you could instead construct a "fresh" MemCachedObjectStore for each "session", with this This would not only avoid changes to object_store, breaking or otherwise, but also allow maximum flexibility on what state comprises a session, and avoid needing to propagate this session state through every ObjectStore interaction. |
@tustvold I considered something like that, but the problem is that we pass the While it's not totally clear to me if the parquet file accesses that we care are about are happening in those core crates or the datafusion runtime using this It's also not clear to me whether we could get a session-scoped span threaded in to an objectstore through the datafusion engine. But I have observed something similar happening for the |
I'm not familiar with how the OSS InfluxDb handles this, but the closed source Influx at least used to construct a SessionContext for each query. This would be an ideal opportunity to construct the instrumented MemCachedObjectStore, and registering it as I believe this should just be a relatively straightforward plumbing exercise. TBC designing and then stabilising a session abstraction for object_store is a non-trivial piece of work, and I'd be very wary about it, it isn't immediately obvious to me that a generic abstraction is even possible |
While I'm still learning my way around this code, this suggestion is somewhat at odds with my understanding of how spans ideally work. You're saying that at the bottom level of a query call stack we should create a SessionContext (or rather, a SpanContext since that's what we're interested in reporting spans to a trace collector like Jaeger) and pass that in to an The problem with this is that the span for any of the To be clear, when I'm talking about spans this is what I mean: https://www.jaegertracing.io/docs/2.3/terminology/#span
Yeah, I realize it's a big ask. I definitely appreciate your time discussing this!
I was trying to illustrate how it might be possible by using the existing |
I believe it already does this, the SessionContext is constructed per query.
I suspect this is inevitable unless tracing were integrated into DataFusion as a first-class concept. Currently the tracing for DataFusion is constructed based on the timing metrics collected during execution. This is itself an approximation, e.g. it aggregates across partitions, to keep trace size manageable. I suspect if you wanted to parent the ObjectStore interactions with the corresponding DF spans, you would need to somehow integrate the ObjectStore interactions with this same metrics system... Ultimately having ObjectStore spans as siblings of the TableProvider spans, maybe not ideal, but would be better than nothing |
I'm not entirely sure what you mean here, do you have a code example I could look at to get a better understanding? I hadn't seen any explicit tracing/span reporting anywhere in datafusion (but I also haven't spent much time digging around the code yet).
I think we can avoid tracing as a first-class concept in Datafusion and get properly-parented spans. One way to do that is what I've proposed in this issue, but I understand it's a big ask with some maybe unpalatable complexity. Another way that should work in the contexts I care about that I was just chatting about with @crepererum this morning would be to update The only thing I'm not certain about with that approach is whether the parquet file access that we care about in influxdb3 are actually using For what it's worth I am also looking into trying out a per-query wrapper around the |
I'm not sure what you mean by this, the DF spans are created after the fact based on its metrics, they don't exist at the time the calls are made to ObjectStore. I therefore don't see how you would correctly parent the ObjectStore spans into the DF tree, when the corresponding spans don't exist until the query has finished executing. See here |
I think we're talking about the same spans, it's just not obvious that the span you're talking are child spans of the query spans that I care about so I'll try to show in a step-by-step fashion how they're related: That root span gets passed to the Then passed to the
Which attaches a
Next it uses the IOxSessionContext to create a physical plan:
.... and so on. I don't think it's important that you look at all those links, I just wanted to illustrate that at any point in that hierarchy the span should already be threaded through in an opaque way -- without DF being made explicitly aware that there is a span being passed through. This is possible because of the It's this span that gets carried all the way through the DF engine call stack that I would like to be able to pass to object store method calls such that In fact, I see how the Which calls Which creates a That Sorry if that's explaining a bunch of stuff you already know, I'm just trying to be as clear as possible about my reasoning.
The part that's hard for me to understand being so new to this code is, where do the object store calls actually happen? That's something I haven't seen but I think someone mentioned this morning during a team sync that I should look into types that wrap the object store for the sake of reading parquet files. That could be this That appears to be used in the The If we were to go with the We would also have to change If we go with the other approach, of using |
They happen as part of physical execution, the spans for which are created as I described above from the metrics set. The spans you are linking to above are from logical and physical planning, not execution. Perhaps @crepererum can weigh in here, as this conversation is somewhat going in circles. TBC adding some sort of dyn Any context type to *Options is probably fine and a useful extension point, doubling the API surface with a load of |
I had a chat w/ @tustvold and I agree w/ him that adding a new method doesn't sound good. Adding an extension point to struct Extensions {
inner: HashMap<TypeId, Box<dyn Extension>>,
}
impl Extensions {
pub fn get::<T>(&self) -> Option<&T> where T: Extension {
self.inner.get(TypeId::of::<T>()).map(|ext| {
ext.as_any().downcast_ref().expect("correct type IDs are enforced by the compiler")
})
}
pub fn set::<T>(&self, ext: T) -> Option<T> where T: Extension {
self.inner.insert(TypeId::of::<T>(), Box::new(ext)).map(|ext| {
ext.as_any().downcast_ref().expect("correct type IDs are enforced by the compiler")
})
}
}
impl PartialEq for Extensions {
// ...
}
trait Extensions: PartialEq<Self> + std::fmt::Debug {
fn as_any(&self) -> &dyn Any;
}
// other module
pub struct GetOptions {
// current stuff
// ...
extensions: Extensions,
} This is roughly modeled after |
Okay, sounds good to me. I'll close this in favor of apache/arrow-rs-object-store#17 |
Is your feature request related to a problem or challenge? Please describe what you are trying to do.
In influxdata/influxdb#25911, we are discussing ways to record
trace
spans that distinguish between two key code paths in an implementation ofObjectStore
that either retrieves objects from an object store or from a local in-memory cache. The problem we have right now is that ourObjectStore
implementation has no way to receive span info passed in from the calling context.Describe the solution you'd like
This issue is proposing the following:
Session
trait to theobject_store
crate similar to what exists in thedatafusion::catalog
datafusion::prelude::SessionConfig
set_extension
,with_extension
, andget_extension
methods that allow storing and retrievingArc<dyn Any + Send + Sync + 'static>
instances by type IDObjectStore
trait take&dyn Session
as a parameterfn get_with_session(&self, session: &dyn Session, location: &Path)
get_with_session
would just ignore the session parameter and callget
by default) to avoid forcing existing implementers to changeThis would allow me to do some refactoring in https://github.com/influxdata/influxdb/ and https://github.com/influxdata/influxdb3_core/ that would result in passing a
&dyn Session
with a properly-parented child span and a custom*_with_session
defined in impl ObjectStore for MemCachedObjectStore -- resulting in trace spans properly contextualized in the hierarchy of a given query which also differentiate between calls that result in cached vs object store parquet file retrieval.Describe alternatives you've considered
I've considered:
MemcachedObjectStore
with its own root hierarchy of spansAdditional context
The text was updated successfully, but these errors were encountered: