@Override public void addAllRecentTo(Collection<String> allRecent) { try (AutoLock al = lock.autoReadLock()) { allRecent.addAll(recentIDs); } }
private MutableSet<String> doGetKnownItems(String user) { try (AutoLock al = knownItemsLock.autoReadLock()) { return knownItems.get(user); } }
@Override public void removeAllIDsFrom(Collection<String> allIDs) { try (AutoLock al = lock.autoReadLock()) { allIDs.removeAll(vectors.keySet()); } }
/** * @param action function to apply to every ID/vector pair */ public void forEach(BiConsumer<String,float[]> action) { try (AutoLock al = lock.autoReadLock()) { vectors.forEach(action); } }
@Override public float[] getVector(String id) { try (AutoLock al = lock.autoReadLock()) { return vectors.get(id); } }
@Override public void addAllIDsTo(Collection<String> allIDs) { try (AutoLock al = lock.autoReadLock()) { allIDs.addAll(vectors.keySet()); } }
@Override public double[] getVTV(boolean background) { // 'background' is ignored try (AutoLock al = lock.autoReadLock()) { return VectorMath.transposeTimesSelf(vectors.values()); } }
@Override public float[] getVector(String item) { // Partitioner isn't used here to compute partition, because for at least one use case // the partitioner might change its answer over time. int partition; try (AutoLock al = partitionMapLock.autoReadLock()) { partition = partitionMap.getIfAbsent(item, Integer.MIN_VALUE); } if (partition < 0) { return null; } return partitions[partition].getVector(item); }
@Override public float getFractionLoaded() { int expected = 0; try (AutoLock al = expectedUserIDsLock.autoReadLock()) { expected += expectedUserIDs.size(); } try (AutoLock al = expectedItemIDsLock.autoReadLock()) { expected += expectedItemIDs.size(); } if (expected == 0) { return 1.0f; } float loaded = (float) X.size() + Y.size(); return loaded / (loaded + expected); }
@Override public float getFractionLoaded() { int expected = 0; try (AutoLock al = expectedUserIDsLock.autoReadLock()) { expected += expectedUserIDs.size(); } try (AutoLock al = expectedItemIDsLock.autoReadLock()) { expected += expectedItemIDs.size(); } if (expected == 0) { return 1.0f; } float loaded = (float) getNumUsers() + getNumItems(); return loaded / (loaded + expected); }
/** * @return mapping of user IDs to count of items the user has interacted with */ public Map<String,Integer> getUserCounts() { Map<String,Integer> counts; try (AutoLock al = knownItemsLock.autoReadLock()) { counts = new HashMap<>(knownItems.size()); knownItems.forEach((userID, ids) -> { int numItems; synchronized (ids) { numItems = ids.size(); } counts.put(userID, numItems); }); } return counts; }
/** * @return mapping of item IDs to count of users that have interacted with that item */ public Map<String,Integer> getItemCounts() { ObjectIntHashMap<String> counts = ObjectIntHashMap.newMap(); try (AutoLock al = knownItemsLock.autoReadLock()) { knownItems.values().forEach(ids -> { synchronized (ids) { ids.forEach(id -> counts.addToValue(id, 1)); } }); } // No way to get Java map from primitive map directly (?) Map<String,Integer> javaCounts = new HashMap<>(counts.size()); counts.forEachKeyValue(javaCounts::put); return javaCounts; }
/** * Like {@link #retainRecentAndUserIDs(Collection)} and {@link #retainRecentAndItemIDs(Collection)} * but affects the known-items data structure. * * @param users users that should be retained, which are coming in the new model updates * @param items items that should be retained, which are coming in the new model updates */ void retainRecentAndKnownItems(Collection<String> users, Collection<String> items) { // Keep all users in the new model, or, that have been added since last model MutableSet<String> recentUserIDs = UnifiedSet.newSet(); X.addAllRecentTo(recentUserIDs); try (AutoLock al = knownItemsLock.autoWriteLock()) { knownItems.keySet().removeIf(key -> !users.contains(key) && !recentUserIDs.contains(key)); } // This will be easier to quickly copy the whole (smallish) set rather than // deal with locks below MutableSet<String> allRecentKnownItems = UnifiedSet.newSet(); Y.addAllRecentTo(allRecentKnownItems); Predicate<String> notKeptOrRecent = value -> !items.contains(value) && !allRecentKnownItems.contains(value); try (AutoLock al = knownItemsLock.autoReadLock()) { knownItems.values().forEach(knownItemsForUser -> { synchronized (knownItemsForUser) { knownItemsForUser.removeIf(notKeptOrRecent); } }); } }
@Test public void testReadLock() { ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); AutoReadWriteLock al = new AutoReadWriteLock(lock); assertEquals(0, lock.getReadLockCount()); try (AutoLock al2 = al.autoReadLock()) { assertEquals(1, lock.getReadLockCount()); } assertEquals(0, lock.getReadLockCount()); }
@Override public void addAllRecentTo(Collection<String> allRecent) { try (AutoLock al = lock.autoReadLock()) { allRecent.addAll(recentIDs); } }
@Override public void removeAllIDsFrom(Collection<String> allIDs) { try (AutoLock al = lock.autoReadLock()) { allIDs.removeAll(vectors.keySet()); } }
@Override public float[] getVector(String id) { try (AutoLock al = lock.autoReadLock()) { return vectors.get(id); } }
/** * @param action function to apply to every ID/vector pair */ public void forEach(BiConsumer<String,float[]> action) { try (AutoLock al = lock.autoReadLock()) { vectors.forEach(action); } }
@Override public void addAllIDsTo(Collection<String> allIDs) { try (AutoLock al = lock.autoReadLock()) { allIDs.addAll(vectors.keySet()); } }
@Override public double[] getVTV(boolean background) { // 'background' is ignored try (AutoLock al = lock.autoReadLock()) { return VectorMath.transposeTimesSelf(vectors.values()); } }