Github user ctubbsii commented on a diff in the pull request:
https://github.com/apache/accumulo/pull/292#discussion_r132825236
--- Diff:
core/src/main/java/org/apache/accumulo/core/client/impl/Table.java ---
@@ -16,24 +16,59 @@
*/
package org.apache.accumulo.core.client.impl;
+import java.lang.ref.WeakReference;
+import java.util.WeakHashMap;
+
import org.apache.accumulo.core.client.Instance;
public class Table {
/**
* Object representing an internal table ID. This class was created to
help with type safety. For help obtaining the value of a table ID from
Zookeeper, see
* {@link Tables#getTableId(Instance, String)}
+ *
+ * Uses an internal WeakHashMap and private constructor for storing a
WeakReference of every Table.ID. Therefore, a Table.ID can't be instantiated
outside
+ * this class and is accessed by calling Table.ID.{@link #of(String)}.
*/
public static class ID extends AbstractId {
private static final long serialVersionUID = 7399913185860577809L;
+ static final WeakHashMap<String,WeakReference<Table.ID>> tableIds =
new WeakHashMap<>();
- public static final ID METADATA = new ID("!0");
- public static final ID REPLICATION = new ID("+rep");
- public static final ID ROOT = new ID("+r");
+ public static final ID METADATA = of("!0");
+ public static final ID REPLICATION = of("+rep");
+ public static final ID ROOT = of("+r");
- public ID(final String canonical) {
+ private ID(final String canonical) {
super(canonical);
}
+
+ /**
+ * Get a Table.ID object for the provided canonical string.
+ *
+ * @param canonical
+ * table ID string
+ * @return Table.ID object
+ */
+ public static Table.ID of(final String canonical) {
+ return dedupeTableId(canonical);
+ }
+
+ private static Table.ID dedupeTableId(String tableIdString) {
+ Table.ID tableId;
+ synchronized (tableIds) {
+ WeakReference<Table.ID> tableIdRef = tableIds.get(tableIdString);
+ if (tableIdRef != null) {
+ tableId = tableIdRef.get();
+ if (tableId != null) {
+ return tableId;
+ }
+ }
+
+ tableId = new ID(tableIdString);
+ tableIds.put(tableIdString, new WeakReference<>(tableId));
--- End diff --
I was thinking through the logic of this put method (and it's "compute"
alternatives), and realized that there's no way to get a strong reference to
the key itself from the map. You can only do comparisons. So, there's a chance
that when you do a "put" here, it will reuse the old key, but the new value (in
the case where the map entry exists, but the WeakReference is empty). The
result is that the entry could disappear from the map even though the object in
the WeakReference is still being used. In this case, we lose deduplication.
There does not appear to be a solution to this (short of writing our own map
class, or iterating over the keyset and comparing keys ourselves), and our
deduplication is "best effort", so it's not a big deal... but it's worth
keeping in mind, so we don't even try to use this paradigm for guaranteed
deduplication.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---