Prevent CachedContentIndex.idToKey from growing without bound
PiperOrigin-RevId: 246727723
This commit is contained in:
parent
1292a35ec6
commit
b53ac32b8c
@ -89,6 +89,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
* efficiently when the index is next stored.
|
* efficiently when the index is next stored.
|
||||||
*/
|
*/
|
||||||
private final SparseBooleanArray removedIds;
|
private final SparseBooleanArray removedIds;
|
||||||
|
/** Tracks ids that are new since the index was last stored. */
|
||||||
|
private final SparseBooleanArray newIds;
|
||||||
|
|
||||||
private Storage storage;
|
private Storage storage;
|
||||||
@Nullable private Storage previousStorage;
|
@Nullable private Storage previousStorage;
|
||||||
@ -150,6 +152,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
keyToContent = new HashMap<>();
|
keyToContent = new HashMap<>();
|
||||||
idToKey = new SparseArray<>();
|
idToKey = new SparseArray<>();
|
||||||
removedIds = new SparseBooleanArray();
|
removedIds = new SparseBooleanArray();
|
||||||
|
newIds = new SparseBooleanArray();
|
||||||
Storage databaseStorage =
|
Storage databaseStorage =
|
||||||
databaseProvider != null ? new DatabaseStorage(databaseProvider) : null;
|
databaseProvider != null ? new DatabaseStorage(databaseProvider) : null;
|
||||||
Storage legacyStorage =
|
Storage legacyStorage =
|
||||||
@ -206,6 +209,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
idToKey.remove(removedIds.keyAt(i));
|
idToKey.remove(removedIds.keyAt(i));
|
||||||
}
|
}
|
||||||
removedIds.clear();
|
removedIds.clear();
|
||||||
|
newIds.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,11 +254,19 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
CachedContent cachedContent = keyToContent.get(key);
|
CachedContent cachedContent = keyToContent.get(key);
|
||||||
if (cachedContent != null && cachedContent.isEmpty() && !cachedContent.isLocked()) {
|
if (cachedContent != null && cachedContent.isEmpty() && !cachedContent.isLocked()) {
|
||||||
keyToContent.remove(key);
|
keyToContent.remove(key);
|
||||||
storage.onRemove(cachedContent);
|
int id = cachedContent.id;
|
||||||
// Keep an entry in idToKey to stop the id from being reused until the index is next stored.
|
boolean neverStored = newIds.get(id);
|
||||||
idToKey.put(cachedContent.id, /* value= */ null);
|
storage.onRemove(cachedContent, neverStored);
|
||||||
// Track that the entry should be removed from idToKey when the index is next stored.
|
if (neverStored) {
|
||||||
removedIds.put(cachedContent.id, /* value= */ true);
|
// The id can be reused immediately.
|
||||||
|
idToKey.remove(id);
|
||||||
|
newIds.delete(id);
|
||||||
|
} else {
|
||||||
|
// Keep an entry in idToKey to stop the id from being reused until the index is next stored,
|
||||||
|
// and add an entry to removedIds to track that it should be removed when this does happen.
|
||||||
|
idToKey.put(id, /* value= */ null);
|
||||||
|
removedIds.put(id, /* value= */ true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,8 +309,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
private CachedContent addNew(String key) {
|
private CachedContent addNew(String key) {
|
||||||
int id = getNewId(idToKey);
|
int id = getNewId(idToKey);
|
||||||
CachedContent cachedContent = new CachedContent(id, key);
|
CachedContent cachedContent = new CachedContent(id, key);
|
||||||
keyToContent.put(cachedContent.key, cachedContent);
|
keyToContent.put(key, cachedContent);
|
||||||
idToKey.put(cachedContent.id, cachedContent.key);
|
idToKey.put(id, key);
|
||||||
|
newIds.put(id, true);
|
||||||
storage.onUpdate(cachedContent);
|
storage.onUpdate(cachedContent);
|
||||||
return cachedContent;
|
return cachedContent;
|
||||||
}
|
}
|
||||||
@ -435,7 +448,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
/**
|
/**
|
||||||
* Ensures incremental changes to the index since the initial {@link #initialize(long)} or last
|
* Ensures incremental changes to the index since the initial {@link #initialize(long)} or last
|
||||||
* {@link #storeFully(HashMap)} are persisted. The storage will have been notified of all such
|
* {@link #storeFully(HashMap)} are persisted. The storage will have been notified of all such
|
||||||
* changes via {@link #onUpdate(CachedContent)} and {@link #onRemove(CachedContent)}.
|
* changes via {@link #onUpdate(CachedContent)} and {@link #onRemove(CachedContent, boolean)}.
|
||||||
*
|
*
|
||||||
* @param content The key to content map to persist.
|
* @param content The key to content map to persist.
|
||||||
* @throws IOException If an error occurs persisting the index.
|
* @throws IOException If an error occurs persisting the index.
|
||||||
@ -453,8 +466,10 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
* Called when a {@link CachedContent} is removed.
|
* Called when a {@link CachedContent} is removed.
|
||||||
*
|
*
|
||||||
* @param cachedContent The removed {@link CachedContent}.
|
* @param cachedContent The removed {@link CachedContent}.
|
||||||
|
* @param neverStored True if the {@link CachedContent} was added more recently than when the
|
||||||
|
* index was last stored.
|
||||||
*/
|
*/
|
||||||
void onRemove(CachedContent cachedContent);
|
void onRemove(CachedContent cachedContent, boolean neverStored);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@link Storage} implementation that uses an {@link AtomicFile}. */
|
/** {@link Storage} implementation that uses an {@link AtomicFile}. */
|
||||||
@ -540,7 +555,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemove(CachedContent cachedContent) {
|
public void onRemove(CachedContent cachedContent, boolean neverStored) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,9 +871,13 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemove(CachedContent cachedContent) {
|
public void onRemove(CachedContent cachedContent, boolean neverStored) {
|
||||||
|
if (neverStored) {
|
||||||
|
pendingUpdates.delete(cachedContent.id);
|
||||||
|
} else {
|
||||||
pendingUpdates.put(cachedContent.id, null);
|
pendingUpdates.put(cachedContent.id, null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Cursor getCursor() {
|
private Cursor getCursor() {
|
||||||
return databaseProvider
|
return databaseProvider
|
||||||
|
Loading…
x
Reference in New Issue
Block a user