Hey Everyone,

Thanks Gábor, I think the proposed interface would be very useful to any
engine that employs caching, e.g. Impala.
And it is pretty neat that it is catalog-agnostic, i.e. we just give
all the information we have about the table and let the catalog
implementation efficiently reload it.

I might have a nitpick suggestion about the name to clearly express the
intent: loadTable -> reloadTable (or, refreshTable)

Cheers,
    Zoltan


On Mon, Nov 18, 2024 at 5:17 PM Gabor Kaszab
<gaborkas...@cloudera.com.invalid> wrote:

> Hi Iceberg Community,
>
> This is a great conversation so far, and thanks everyone for the valuable
> inputs!
> I'd like to articulate 2 things that we have to keep in mind with the
> design:
>
> *1: There are 2 interfaces here that we should consider:*
> What I mean by this is that so far we have been talking about the REST
> spec, more narrowly the HTTP communication between Iceberg's REST client
> and the REST server. I think the proposed solution with the ETag absolutely
> makes sense within this context.
> However, the usual way of a client interacting with an Iceberg catalog
> (including REST) is the Catalog API in the library. This API offers a
> loadTable(TableIdentifier) function that returns a Table object. With the
> above HTTP-based solution in mind I don't think we could give any
> meaningful results if the HTTP layer finds that the table hasn't changed. I
> argued already against pushing the caching responsibilities from the
> clients into the HTTP layer (mostly because of losing the control over the
> cache, and also observability won't be straightforward) so let's assume for
> now that we won't do caching in the HTTP layer, only execute the loadTable
> calls to the REST catalog by setting the ETag. In case we get a 304 we
> won't be able to construct a Table object to answer the
> Catalog.loadTable(TableIdentifier) call. We could return null or throw an
> exception but I don't find any of them appropriate.
>
> *2: There are catalog types other than REST*
> I started this conversation focusing on the REST spec, but the more I
> think of this the more I feel that the same functionality should be offered
> for all the other catalog types too. Let's assume that we have an engine
> that caches table metadata and initially uses REST catalog. For such an
> engine the proposed solution would solve the problem of checking table
> freshnes and also reloading the table metadata. A simple code for that
> could be enough if we configured our HTTP client properly (just sketched a
> simple example):
>
> tableCache_.put(catalog_.loadTable(tableIdentifier));
>
> Also let's assume we solve the issue in 1) and we can answer such a call
> even if we get 304 from the server as the table is unchanged. So with this
> solution with the REST catalog we can be sure that the table is only loaded
> from the catalog if changed (or the age expired). But what if we configure
> another catalog, let's say HiveCatalog. The very same code for that catalog
> would trigger a table reload for every execution causing unexpected
> performance issues.
> I have to double check but I assume that this HTTP approach wouldn't be
> feasible for other catalog types unfortunately.
>
> I hope these arguments make sense :)
>
>
> *As a partial solution this is what I have in mind:*
> We can add another function into the catalog API for this purpose. Let's
> say something like this:
> Table loadTable(Table existingTable);
>
> What advantages I see with this:
> - This could solve issue 1) above. In case the table hasn't changed we can
> simply return 'existingTable' without using HTTP Cache.
> - The clients wouldn't need to explicitly call for isLatest() and such
> functions to check for freshness, and they wouldn't need to trigger table
> reloading for themselve. This API would be expected to cover this under the
> hood.
> - The current Catalog.loadTable(TableIdentifier) API wouldn't be enough
> for all the catalog types on it's own, but with this one each catalog
> implementations (e.g. HiveCatalog, REST catalog, etc.) then can implement
> their own way of doing freshness checks and table reloads. For REST we
> could follow the HTTP ETag approach, while for other catalogs we could
> follow other approaches.
>
> Regards,
> Gabor
>
> On Mon, Nov 18, 2024 at 8:48 AM Shani Elharrar <sh...@upsolver.com.invalid>
> wrote:
>
>> You're totally right. Perhaps using a "Content-Location" header might be
>> a better fit for that.
>>
>> Shani.
>>
>> On 18 Nov 2024, at 9:27, Taeyun Kim <taeyun....@innowireless.com> wrote:
>>
>> 
>> Hi,
>>
>> Here are my thoughts:
>>
>> - The value of ETag is (as far as I know) defined as an opaque string by
>> the specification, meaning the client shouldn’t interpret or assign any
>> significance to it, regardless of what the server specifies. It’s best to
>> avoid the client giving any particular meaning to the ETag value.
>> - One major advantage of the header approach compared to other methods is
>> that if an update has occurred, the updated content can be immediately
>> included in the response without requiring an additional request. This
>> saves one request-response round-trip (although It’s also possible to
>> define a separate endpoint with the same functionality).
>> - Since the Iceberg REST catalog server is effectively a type of HTTP
>> server, at least in theory, it may be expected to handle HTTP cache and
>> validation-related processes. The header approach can be seen as leveraging
>> this mechanism appropriately.
>> - The header approach doesn’t have to be limited to the
>> /v1/{prefix}/namespaces/{namespace}/tables/{table} endpoint. It could also
>> be applied to all GET-based endpoints, though this might broaden the scope
>> significantly.
>>
>> Thank you.
>>
>>
>>
>> -----Original Message-----
>> From: "Shani Elharrar" <sh...@upsolver.com.invalid>
>> To: <dev@iceberg.apache.org>;
>> Cc: <dev@iceberg.apache.org>;
>> Sent: 2024-11-18 (월) 16:21:16 (UTC+09:00)
>> Subject: Re: [DISCUSS] REST: Way to query if metadata pointer is the
>> latest
>>
>> Using the metadata file name as ETag is nice way to go. In that case,
>> adding HEAD method support to the loadTable endpoint will return the latest
>> metadata pointer, which can be used to support "isLatest" without returning
>> the body. It can be also leveraged in order to return the latest metadata
>> location of the table.
>>
>> Shani.
>>
>> On 18 Nov 2024, at 8:52, Yufei Gu <flyrain...@gmail.com> wrote:
>>
>> 
>>
>> Hi Taeyun,
>>
>> Thank you for the clear explanation.
>>
>> I agree that the ETag solution is more suitable. If we were going that
>> way, I'd propose a customized version number as an ETag—for instance,
>> leveraging the metadata.json file name as the identifier.
>>
>> To summarize, HTTP caching relies on headers (e.g., ETag or
>> Last-Modified) to validate whether a version is up-to-date, whereas the
>> alternative approach proposed above uses an additional parameter for
>> verification. From my perspective, there isn’t a fundamental difference
>> between the two, so I’m OK with either.
>>
>> A couple of points to note:
>>
>>    1. Both approaches would require changes to the "loadTable" endpoint.
>>    2. A minor advantage of HTTP caching is that it integrates seamlessly
>>    with browsers, but since most clients of the Iceberg REST catalog aren’t
>>    browsers, this may not be a significant factor.
>>    3. I’d also recommend considering the requirement to retrieve
>>    multiple tables(e.g., all tables under a namespace, or a list of table
>>    names) from the catalog. This requires a new endpoint and may not work 
>> with
>>    HTTP caching.
>>
>> Let me know your thoughts or if there’s anything else to consider.
>> Yufei
>>
>>
>> On Sun, Nov 17, 2024 at 6:43 PM Taeyun Kim <taeyun....@innowireless.com>
>> wrote:
>>
>> Hi,
>>
>> To Gabor:
>> It doesn’t seem necessary to interpret HTTP caching literally in this
>> context.
>> Simply using the HTTP headers defined by HTTP caching to check the
>> freshness of metadata should be sufficient.
>> There’s no requirement for the client to duplicate or store cached HTTP
>> responses.
>>
>> To Yufei:
>> As I understand it, the client doesn’t send its own timestamp but instead
>> uses the timestamp originally provided by the server in the Last-Modified
>> header.
>> Therefore, clock synchronization issues should not be a concern.
>>
>> Here’s the general flow of HTTP cache validation based on
>> If-Modified-Since:
>>
>> - Client: initial request:
>>
>> GET (url) HTTP/1.1
>>
>> - Server response:
>>
>> HTTP/1.1 200 OK
>> Last-Modified: (date1)
>> Cache-Control: no-store, no-cache, max-age=0, must-revalidate,
>> proxy-revalidate
>> (with response body)
>>
>> - Client: validation request:
>>
>> GET (url) HTTP/1.1
>> If-Modified-Since: (date1)
>>
>> - Server response (if unchanged):
>>
>> HTTP/1.1 304 Not Modified
>> Last-Modified: (date1)
>> Cache-Control: no-store, no-cache, max-age=0, must-revalidate,
>> proxy-revalidate
>> (without response body)
>>
>> - Server response (if updated):
>>
>> HTTP/1.1 200 OK
>> Last-Modified: (date2)
>> Cache-Control: no-store, no-cache, max-age=0, must-revalidate,
>> proxy-revalidate
>> (with response body)
>>
>> However, using time-based freshness checks can present challenges, such
>> as parsing time formats or synchronizing file update times across servers.
>> To address these issues, HTTP cache validation based on ETag is also
>> defined in the specification.
>>
>> Here’s the flow for ETag-based validation:
>>
>> - Client: initial request:
>>
>> GET (url) HTTP/1.1
>>
>> - Server response:
>>
>> HTTP/1.1 200 OK
>> ETag: "(arbitrary string 1 generated by the server)"
>> Cache-Control: no-store, no-cache, max-age=0, must-revalidate,
>> proxy-revalidate
>> (with response body)
>>
>> - Client: validation request:
>>
>> GET (url) HTTP/1.1
>> If-None-Match: "(arbitrary string 1 generated by the server)"
>>
>> - Server response (if unchanged):
>>
>> HTTP/1.1 304 Not Modified
>> ETag: "(arbitrary string 1 generated by the server)"
>> Cache-Control: no-store, no-cache, max-age=0, must-revalidate,
>> proxy-revalidate
>> (without response body)
>>
>> - Server response (if updated):
>>
>> HTTP/1.1 200 OK
>> ETag: "(arbitrary string 2 generated by the server)"
>> Cache-Control: no-store, no-cache, max-age=0, must-revalidate,
>> proxy-revalidate
>> (with response body)
>>
>> The server can choose to use either If-Modified-Since or ETag for
>> freshness validation.
>> Alternatively, to simplify the implementation related to the Iceberg REST
>> catalog, it might make sense to define only the more accurate ETag-based
>> validation in the spec.
>> For reference, RFC 9110 recommends specifying both ETag and
>> Last-Modified. When both are provided, ETag takes precedence.
>>
>> Note on Cache-Control Headers:
>> The Cache-Control values in the examples above are intended to ensure
>> that the client validates freshness with the server on every request.
>> Writing the header in this extended format is primarily to accommodate
>> outdated HTTP/1.1 implementations. However, under the HTTP/1.1
>> specification, the following is sufficient:
>>
>> Cache-Control: no-cache
>>
>> That’s all for now.
>> Thank you.
>>
>>
>> -----Original Message-----
>> From: "Yufei Gu" <flyrain...@gmail.com>
>> To: <dev@iceberg.apache.org>;
>> Cc:
>> Sent: 2024-11-16 (토) 02:51:05 (UTC+09:00)
>> Subject: Re: [DISCUSS] REST: Way to query if metadata pointer is the
>> latest
>>
>>
>>
>> How does HTTP caching handle desynchronized clocks between clients and
>> the server?
>>
>> At t0, the client gets the latest table version.
>> At t1, the server makes a new commit.
>> At t2, the client sends a request with a timestamp t2, but due to
>> desynchronization, it refers to t0.
>>
>> The server may reply with 304 Not Modified, causing the client to think
>> its cache is up-to-date and miss the commit at t1.
>>
>>
>>
>> Yufei
>>
>>
>>
>>
>> On Fri, Nov 15, 2024 at 6:37 AM Gabor Kaszab <gaborkas...@apache.org>
>> wrote:
>> Hi All,
>>
>>
>> First of all it's great to see that there are others who could benefit
>> from giving a solution to this problem. I appreciate all the comments and
>> feedback so far.
>> There were a number of different opinions, so let me start with
>> summarizing the different topics that came up:
>>
>>
>> New endpoint vs using an existing endpoint:
>> Based on the answers (Fokko, Yufei) I had the impression that we should
>> be careful when adding new REST endpoints, and we should examine the re-use
>> of existing endpoints first. Let's do that then, and in case we don't find
>> it feasible then we can still fall back to any of my initial proposals
>> (isLatest() or metadataLocation()).
>>
>>
>> Granularity of freshness checks:
>> It was brought up (Dmitri) that we might not want to do the metadata
>> freshness checks solely based on metadata location, but we should consider
>> doing more granular freshness checks. I personally don't see much benefit
>> of designing this solution like that, TBH, but seeing some use-cases could
>> help us understand the motivation here.
>> Let me share my opinion on some of the arguments:
>>
>>
>> "A change in metadata location does not necessarily mean a change in
>> metadata content"
>>
>>
>> AFAIK whenever Iceberg creates a new metadata file there is some change
>> in the metadata itself. There might not be a new snapshot, though in the
>> cases of e.g. a schema/partition evolution. But even in these cases
>> triggering a table reload could make sense to me (e.g. answering SHOW
>> CREATE TABLE and similar queries). Additionally, I'd assume the number of
>> metadata location changes that don't create a new snapshot is too
>> negligible to optimize for.
>> Dmitri, let me know if I misunderstood something.
>>
>>
>> "it may still be beneficial to permit the client to ask for changes to
>> specific areas of metadata"
>>
>> This seems like a use-case that the partial metadata loading proposal
>> could solve. To identify the need to load a specific part of the metadata
>> with partial metadata loading seems an overkill to design with my proposal,
>> if this is what you have in mind. Also I found that the partial metadata
>> loading proposal faces serious headwinds, so I wouldn't rely on it at the
>> moment.
>>
>>
>> Re-using tableExists
>> I think there is a consensus here that tableExists returning a metadata
>> location could work but seems more like a workaround and could be
>> misleading for the users.
>>
>> Partial metadata loading could solve this:
>> (Yufei) I agree, it would be perfect for my use-case and I'm following
>> the discussion on the proposal. However, for me it seems, as I wrote above,
>> that the proposal faces serious headwinds now and I honestly wouldn't
>> expect a solution in the short term. But solving the freshness problems is
>> a more urgent thing to solve, not just for myself and Impala but apparently
>> to many other stakeholders in the community according to the interest on
>> this thread.
>> Hence, I propose to come up with a separate solution for freshness
>> checks, and we can still move to using partial metadata loading once that's
>> out.
>>
>>
>> Use HTTPCache and If-Modified-Since with loadTable
>> This solution seems to do the trick for us. Let me do some research
>> myself to see if there are any difficulties implementing this. Currently, I
>> have more questions than answers wrt this approach :)
>> - The initial problem is to answer freshness questions for the cached
>> tables on the client side. If we introduce HttpCaching wouldn't we
>> introduce the same problem but on a different level of representation. We'd
>> then need to decide the freshness/staleness of the cached data in the HTTP
>> layer.
>> - If we cache the HTTP responses for a loadTable then we essentially
>> cache the content of the metadata.jsons including the snapshot and metadata
>> log and everything, plus the snapshot list (and I think the manifests for
>> the latest snapshot). I believe that the size of this can easily reach the
>> low megabytes range in memory, so in total keeping them in the HTTP Cache
>> for all the tables we have queried can easily mean that we keep a couple of
>> GBs in memory just for this purpose.
>> For engines that already cache table metadata wouldn't this mean that we
>> will cache some parts of the metadata redundantly?
>> - How would we decide what is the max-age of a cached table metadata in
>> the HTTP Cache? Would it be configurable so that each engine could use
>> whatever it prefers?
>>
>>
>> Sorry if any of the questions doesn't make sense, I just want to make
>> sure I understand all the aspects of this approach.
>>
>>
>> An additional topic I have in mind:
>> REST catalog vs other catalogs:
>> Now we are focusing our discussion on the REST spec, but I think it would
>> be beneficial to extend our focus and cover other catalog implementations
>> too. I don't think that this problem of data freshness is specific to REST
>> catalog, it could affect any table in any other catalog too.
>>
>>
>> I'll continue my investigation wrt the proposals, I just wanted to flush
>> out and sum up what we have now before the weekend.
>>
>>
>> Regards,
>> Gabor
>>
>>
>>
>>
>> On Fri, Nov 15, 2024 at 10:16 AM Jean-Baptiste Onofré <j...@nanthrax.net>
>> wrote:
>> Hi,
>>
>> I like the idea and it makes sense. As soon as it's clearly stated in
>> the spec (using If-Modified-Since header and 304 status code), it
>> looks good to me.
>>
>> Thanks !
>> Regards
>> JB
>>
>> On Fri, Nov 15, 2024 at 1:58 AM Taeyun Kim <taeyun....@innowireless.com>
>> wrote:
>> >
>> > Hi,
>> >
>> > (Apologies if this email is a duplicate. This is my third attempt.)
>> >
>> > I also need a way to ensure that my table data is up-to-date. For now,
>> I’m handling this by setting an expiration period after which I fetch the
>> data again, regardless of its freshness.
>> >
>> > Here are my thoughts on the current suggestions. Please correct me if
>> I've misunderstood any of the points.
>> >
>> > - isLatest(): This function could be inefficient since it would require
>> an additional round-trip to fetch the metadata if it’s not up-to-date. This
>> would result in two round-trips overall, which seems suboptimal.
>> > - metadataLocation(): This has a similar issue as isLatest(). BTW,
>> according to the REST catalog API documentation for LoadTableResult schema,
>> it states, "Clients can check whether metadata has changed by comparing
>> metadata locations after the table has been created." (
>> https://github.com/apache/iceberg/blob/3659ded18d50206576985339bd55cd82f5e200cc/open-api/rest-catalog-open-api.yaml#L3175)
>> This suggests that if the metadata location has changed, the metadata can
>> be considered updated.
>> > - tableExists(): Based on the name, this function seems to serve a
>> different purpose.
>> >
>> > Here is my suggestion:
>> >
>> > Since HTTP has built-in caching features (
>> https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching), and REST
>> catalogs operate over HTTP, it seems natural to leverage HTTP caching
>> mechanisms. For example, HTTP includes the If-Modified-Since header and the
>> 304 Not Modified status code. Using this approach, we could achieve data
>> freshness with a single round-trip, fetching updated data only if there are
>> modifications.
>> >
>> > What do you think about defining the spec in this direction?
>> >
>> > Thank you.
>> >
>> >
>> >
>> >
>> > -----Original Message-----
>> > From: "Yufei Gu" <flyrain...@gmail.com>
>> > To: <dev@iceberg.apache.org>;
>> > Cc:
>> > Sent: 2024-11-13 (수) 03:43:24 (UTC+09:00)
>> > Subject: Re: [DISCUSS] REST: Way to query if metadata pointer is the
>> latest
>> >
>> >
>> >
>> > Hi Gamber,
>> >
>> > Thanks for the proposal! Impala isn’t unique in needing this—I've seen
>> similar requirements from other engines.
>> >
>> > As others pointed out, using the “tableExists” endpoint seems like a
>> workaround. I don't consider it a permanent way forward. We could address
>> this by either modifying the current load table endpoint or introducing a
>> new one, but ideally, we should avoid adding endpoints for every specific
>> need. With that, partial metadata loading seems like a strong approach
>> here, we will need certain agreement though. I'd suggest the community
>> consider the use cases seriously. We need a way forward.
>> >
>> > I’m also not too concerned about using metadata file paths to verify
>> the latest table version; clients can simply extract metadata filenames,
>> which include the UUID.
>> >
>> > Yufei
>> >
>> >
>> >
>> >
>> > On Tue, Nov 12, 2024 at 7:46 AM Jean-Baptiste Onofré <j...@nanthrax.net>
>> wrote:
>> >
>> > Hi Fokko
>> >
>> > I like the idea, but I think it's more a workaround and could be
>> > confusing for users :)
>> >
>> > Regards
>> > JB
>> >
>> > On Tue, Nov 12, 2024 at 2:53 PM Fokko Driesprong <fo...@apache.org>
>> wrote:
>> > >
>> > > Hey Gabor,
>> > >
>> > > Thanks for raising this. While reading this, my first thought is to
>> leverage the `tableExists` operation:
>> > >
>> https://github.com/apache/iceberg/blob/e3f39972863f891481ad9f5a559ffef093976bd7/open-api/rest-catalog-open-api.yaml#L1129-L1160
>> > >
>> > > This doesn't return anything today, but we could return a payload to
>> the latest metadata.json.
>> > >
>> > > Looking forward to what others think.
>> > >
>> > > Kind regards,
>> > > Fokko
>> > >
>> > >
>> > >
>> > >
>> > > Op di 12 nov 2024 om 14:33 schreef Shani Elharrar
>> <sh...@upsolver.com.invalid>:
>> > >>
>> > >> I recommend option (b), provided there is no partial metadata
>> loading. We implemented option (b) internally to facilitate partial
>> metadata loading, as we have tables with hundreds of thousands of
>> snapshots. This results in metadata that occupies approximately 500 MB in
>> memory (excluding the JsonNodes), which is a significant load for some of
>> our services.
>> > >>
>> > >> Shani.
>> > >>
>> > >> On 12 Nov 2024, at 14:12, Gabor Kaszab <gaborkas...@apache.org>
>> wrote:
>> > >>
>> > >> Hey Iceberg Community,
>> > >>
>> > >> Background:
>> > >> Impala is designed in a way to cache the Iceberg table metadata
>> (BaseTable objects in practice) for faster access. Currently, Impala is
>> tightly coupled with HMS and in turn with the HiveCatalog, and in order to
>> keep the cached table objects up-to-date there is a notification mechanism
>> driven by HMS to notify Impala about any changes in the table metadata.
>> > >> The Impala community is actively looking for ways to decouple HMS
>> from Impala and provide a way to use Impala without the need for HMS, and
>> get the Iceberg table metadata from other catalog Implementations mainly
>> focusing now on REST catalogs.
>> > >>
>> > >> Problem to solve:
>> > >> We identified a particular missing functionality in the current REST
>> spec: For engines that cache table metadata currently there is no way to
>> check if that table metadata is up-to-date or not, and whether the engine
>> should reload the metadata for that table or not without getting a whole
>> table object from the catalog. For this I think the REST catalog (but in
>> fact I think this could apply to any other catalogs) should be able to
>> answer a question like:
>> > >> "Hi Catalog, I have this version of this table, is it up-to-date?"
>> > >>
>> > >> Proposal:
>> > >> I've been following the discussion about partial metadata loading
>> that could be also used to answer the above question, but I have the
>> impression now that the conversation stopped making any progress.
>> > >> So instead of waiting for partial metadata loading I propose to have
>> an addition to the REST spec now to answer the question I raised above:
>> > >>
>> > >> a) boolean isLatest(TableIdentifier ident, String metadataLocation);
>> > >> b) String metadataLocation(TableIdentifier ident);
>> > >>
>> > >> Any of the above 2 approaches could help engines to decide if they
>> have to invalidate/reload particular table metadata in the cache. I
>> personally would go for option a) but would be open to hear other opinions.
>> > >>
>> > >> I'd like to know if the community could support me extending the
>> REST spec with any of the 2 options.
>> > >>
>> > >> Regards,
>> > >> Gabor
>> > >>
>> > >>
>>
>>

Reply via email to