Skip to content
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

G11n java client - Fix for expiration-related issues (issues 604, 664, and 662) #699

Merged
merged 159 commits into from
Aug 14, 2020

Conversation

jessiejuachon
Copy link
Contributor

No description provided.

jessiejuachon and others added 30 commits March 10, 2020 17:00
Signed-off-by: Jessie <jessiejuachon@gmail.com>
…t in order to get a 304 NOT MODIFIED http response
…g file. This means max age from server will be used. Setting VIPCfg.cacheExpiredTime to 0 disables caching.
if (cachedData != null)
private final Map<String, String> cachedData = new HashMap<>();

public synchronized void setCacheItem(String locale, Map<String, String> cachedData, String etag, long timestamp, Long maxAgeMillis) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public synchronized void setCacheItem(String locale, Map<String, String> cachedData, String etag, long timestamp, Long maxAgeMillis) {
public synchronized void setCacheItem(String locale, Map<String, String> dataToCache, String etag, long timestamp, Long maxAgeMillis) {


cacheItem.addCachedData(messages);
cacheItem.setTimestamp(System.currentTimeMillis());
cacheItem.setCacheItem(dto.getLocale(), messages, null, System.currentTimeMillis(), null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to store time to cache because data from local will never expire.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data from local must expire. Use case: If data from local was fetched as a fallback for when Singleton service is temporarily down. In this case, when the cached data from local expires, it should try to fetch from the service again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be set the time in other place because here is Local Opt, it doesn't need to consider the time.

Copy link
Contributor Author

@jessiejuachon jessiejuachon Aug 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So where do you recommend to set the time? By the way, there is nothing about expire time here, only timestamp of when the data was fetched from local bundles. And it has been there before this PR, just combined them into 1 call, so I do not want to make any change about that in this PR.

public synchronized void setMaxAgeMillis(Long maxAgeMillis) {
this.maxAgeMillis = maxAgeMillis;
}
public String getLocale() { return locale; }

public boolean isExpired() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public boolean isExpired() {
public synchronized boolean isExpired() {

@@ -96,7 +96,7 @@ public ComponentsService(final VIPCfg config) {
final MessagesDTO dto = new MessagesDTO();
dto.setComponent(comp);
dto.setLocale(locale);
new CacheService(dto).addCacheOfComponent(new MessageCacheItem(messages, cacheItem.getEtag(),
new CacheService(dto).addCacheOfComponent(new MessageCacheItem(locale, messages, cacheItem.getEtag(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the etag is for all the components instead of a single component. so it's a wrong etag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right! Good catch. I'll set the etag to null for this one for now.
#646

Comment on lines 137 to 138
MessagesDTO fallbackLocaleDTO = new MessagesDTO(dto.getComponent(), cacheItemLocale, dto.getProductID(), dto.getVersion());
new ComponentService(fallbackLocaleDTO).fetchMessages(cacheItem, VIPCfg.getInstance().getMsgOriginsQueue().listIterator());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reasons, the requested locale failed last time. We still need to try the requested locale first, then fallback to default locale if failure.

Copy link
Contributor Author

@jessiejuachon jessiejuachon Aug 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will update line 103 with this: if (cacheItem.isExpired() || !cacheItem.getLocale().equals(this.dto.getLocale())). It should resolve the issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid it can't. If one locale gets the default locale's messages, it will always get the default locale's messages. It's wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right! My mistake. See the changes please

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that the requested locale fails not because locale isn't supported but other reasons such as network error. So next time to update cache, still need to get the requested locale first.

Copy link
Contributor Author

@jessiejuachon jessiejuachon Aug 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is what is happening as I explained to Huihui.

In line 110, if the cache contains the fallback locale and not the requested locale, it will always try to fetch the requested locale first (line 113) and try to assign that to the requested locales cache key (line 116). Only if it fails again will it point to the fallback locale’s cacheItem again (line 122).

populateCacheTask only refreshes the content of the object that is already in the cache (e.g. either the target or fallback locale cacheItem), but it will not change the mapping of the object to the cache key/s. So this line you commented on will not affect the existing mapping/s of the object to cache key/s. It will just update the contents (the insides) of cacheItem object itself.

If you still do not get it, let's connect over Zoom

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have also updated the code to make it easier to understand, but same logic.

@@ -99,7 +99,8 @@ public MessageCacheItem getMessages(Iterator<Locale> fallbackLocalesIter) {
MessageCacheItem cacheItem = null;
if (cacheService.isContainComponent()) { // Item is in cache
cacheItem = cacheService.getCacheOfComponent();
if (cacheItem.isExpired()) { // cacheItem has expired
// If the cacheItem is either expired or for a fallback locale
if (cacheItem.isExpired() || !cacheItem.getLocale().equals(this.dto.getLocale())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this condition !cacheItem.getLocale().equals(this.dto.getLocale()),
cache default locale's content for requested locale may not take effect, because they never be equal.

huihuiw01
huihuiw01 previously approved these changes Aug 12, 2020
Comment on lines +112 to 115
// If the cacheItem is for a fallback locale, create and store cacheItem for the requested locale in a separate thread.
if (!LocaleUtility.isSameLocale(cacheItem.getLocale(), this.dto.getLocale())) {
this.createCacheItemTask(fallbackLocalesIter);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about moving this into above if block so it doesn't fetch every time.

Copy link
Contributor Author

@jessiejuachon jessiejuachon Aug 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually want to always try to fetch for the requested locale every time in a separate thread, not just when the cacheItem has expired. This is because if the cacheItem is for a fallback locale, any other call for a non-supported locale can trigger a refresh of the fallback locale's cacheItem. If that happens, the requested locale may not satisfy the if(cacheItem.isExpired() because the fallback locale has been refreshed by some other request. In this case, we still want to try and fetch the data for the requested locale.

if (!cacheItem.getCachedData().isEmpty()) {
cacheService.addCacheOfComponent(cacheItem);
} else if (!dto.getLocale().equals(ConstantsKeys.SOURCE) && fallbackLocalesIter!=null && fallbackLocalesIter.hasNext()) {
// If failed to fetch message for the requetsed DTO, use MessageCacheItem of the next fallback locale.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to judge if current fallback locale is same as the locale in DTO. If same, should skip it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you follow the recursive logic, the locale in the dto will be the previous locale in the fallback locale queue.

* @param fallbackLocalesIter The fallback locale queue to use in case of failure.
*
*/
private MessageCacheItem createCacheItem(Iterator<Locale> fallbackLocalesIter) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems here has a recursive call: getMessages(Iterator fallbackLocalesIter) -> createCacheItem(Iterator fallbackLocalesIter) -> new ComponentService(fallbackLocaleDTO).getMessages(fallbackLocalesIter)

In my opinion, the hierarchical relation between methods are not clear.

Comment on lines +136 to +142
} else if (!dto.getLocale().equals(ConstantsKeys.SOURCE) && fallbackLocalesIter!=null && fallbackLocalesIter.hasNext()) {
// If failed to fetch message for the requetsed DTO, use MessageCacheItem of the next fallback locale.
MessagesDTO fallbackLocaleDTO = new MessagesDTO(dto.getComponent(), fallbackLocalesIter.next().toLanguageTag(), dto.getProductID(), dto.getVersion());
cacheItem = new ComponentService(fallbackLocaleDTO).getMessages(fallbackLocalesIter);
if (!cacheItem.getCachedData().isEmpty()) {
cacheService.addCacheOfComponent(cacheItem);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here only use the first fallback locale in the fallback locale chain, doesn't go through the whole fallback locale chain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually does go through the whole cahin/queue. In line 138, you see fallbackLocalesIter.next(). By calling .next(), the current pointer of fallbackLocalesIter moves to the next item in the queue. When you pass fallbackLocalesIter to ComponentService.getMessages() in line139, the iterator holds the correct place (current pointer) in the queue.

@jessiejuachon jessiejuachon merged commit 8e5cd6f into vmware:g11n-java-client Aug 14, 2020
huihuiw01 pushed a commit to huihuiw01/singleton that referenced this pull request Aug 19, 2020
…, and 662) (vmware#699)

Fix for expiration-related issues (issues 604, 664, and 662) (vmware#699)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment