| OLD | NEW |
| (Empty) | |
| 1 /* |
| 2 * Copyright 2011 Google Inc. |
| 3 * |
| 4 * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 * you may not use this file except in compliance with the License. |
| 6 * You may obtain a copy of the License at |
| 7 * |
| 8 * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 * |
| 10 * Unless required by applicable law or agreed to in writing, software |
| 11 * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 * See the License for the specific language governing permissions and |
| 14 * limitations under the License. |
| 15 */ |
| 16 package com.google.ipc.invalidation.ticl; |
| 17 |
| 18 import com.google.ipc.invalidation.ticl.proto.ClientProtocol.InvalidationP; |
| 19 import com.google.ipc.invalidation.ticl.proto.ClientProtocol.ObjectIdP; |
| 20 import com.google.ipc.invalidation.util.TypedUtil; |
| 21 |
| 22 import java.util.HashMap; |
| 23 import java.util.Map; |
| 24 |
| 25 /** |
| 26 * An ack "cache" that allows the TICL to avoid unnecessary delivery of a |
| 27 * known-version invalidation when the client has aleady acked a known-version, |
| 28 * restarted invalidation with the same or a greater version number. |
| 29 * <p> |
| 30 * This helps invalidation clients avoid unnecessary syncs against their backend |
| 31 * when invalidations for an object are redelivered or reordered, as can occur |
| 32 * frequently during a PCR or (to a lesser degree) as a result of internal |
| 33 * failures and channel flakiness. |
| 34 * <p> |
| 35 * This optimization is especially useful for applications that want to use |
| 36 * the TI Pubsub API to deliver invalidations, because version numbers are not |
| 37 * a concept in the API itself. While the client could include version numbers |
| 38 * in the payload, truncation messages do not include a payload. |
| 39 * <p> |
| 40 * The cache invalidation API does expose version numbers, so client |
| 41 * applications could implement the same logic themselves, but many |
| 42 * do not, so it is a useful convenience to implement this for them in the TICL. |
| 43 * <p> |
| 44 * Note this class currently only records acks for restarted, known-version |
| 45 * invalidations. While we might add ack tracking for continous invalidations at |
| 46 * some time in the future, tracking continuous invalidations has less of a |
| 47 * payoff than tracking restarted invalidations, because such an ack does not |
| 48 * implicitly ack earlier invalidations for that object, and greater complexity, |
| 49 * because of the potentially unbounded number of acks that need to be tracked |
| 50 * for each object. |
| 51 */ |
| 52 class AckCache { |
| 53 |
| 54 /** |
| 55 * A map from object id to the (long) version number of the highest |
| 56 * <em>restarted, known version</em> invalidation for that object that has |
| 57 * been acked by the client. |
| 58 */ |
| 59 private Map<ObjectIdP, Long> highestAckedVersionMap = new HashMap<ObjectIdP, L
ong>(); |
| 60 |
| 61 /** Records the fact that the client has acknowledged the given invalidation.
*/ |
| 62 void recordAck(InvalidationP inv) { |
| 63 if (!inv.getIsTrickleRestart() || !inv.getIsKnownVersion()) { |
| 64 return; |
| 65 } |
| 66 |
| 67 // If the invalidation version is newer than the highest acked version in th
e |
| 68 // map, then update the map. |
| 69 ObjectIdP objectId = inv.getObjectId(); |
| 70 long version = inv.getVersion(); |
| 71 if (version > getHighestAckedVersion(objectId)) { |
| 72 highestAckedVersionMap.put(objectId, version); |
| 73 } |
| 74 } |
| 75 |
| 76 /** |
| 77 * Returns true if the client has already acked a restarted invalidation with |
| 78 * a version number greater than or equal to that in {@code inv} and the same |
| 79 * object id, and {@code inv} is a known version invalidation. Unknown version |
| 80 * invalidations are never considered already acked. |
| 81 */ |
| 82 boolean isAcked(InvalidationP inv) { |
| 83 return inv.getIsKnownVersion() |
| 84 && this.getHighestAckedVersion(inv.getObjectId()) >= inv.getVersion(); |
| 85 } |
| 86 |
| 87 |
| 88 /** |
| 89 * Returns the highest acked version for the object id with the given key, or |
| 90 * -1 if no versions have been acked. |
| 91 */ |
| 92 private long getHighestAckedVersion(ObjectIdP objectId) { |
| 93 Long version = TypedUtil.mapGet(highestAckedVersionMap, objectId); |
| 94 return (version != null) ? version : -1L; |
| 95 } |
| 96 } |
| OLD | NEW |