Support multiple instances of database features
- Use Cache UID for CacheContentIndex and CacheFileMetadataIndex. This enables SD card swapping for a single device. - I'm hopeful of finding a way to get the Cache UID to DefaultDownloadIndex so we can do the same there. PiperOrigin-RevId: 234662753
This commit is contained in:
parent
5b891a4c1f
commit
2685b8bd90
@ -31,7 +31,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
*/
|
*/
|
||||||
public final class VersionTable {
|
public final class VersionTable {
|
||||||
|
|
||||||
/** Returned by {@link #getVersion(SQLiteDatabase, int)} if the version is unset. */
|
/** Returned by {@link #getVersion(SQLiteDatabase, int, String)} if the version is unset. */
|
||||||
public static final int VERSION_UNSET = -1;
|
public static final int VERSION_UNSET = -1;
|
||||||
/** Version of tables used for offline functionality. */
|
/** Version of tables used for offline functionality. */
|
||||||
public static final int FEATURE_OFFLINE = 0;
|
public static final int FEATURE_OFFLINE = 0;
|
||||||
@ -43,18 +43,26 @@ public final class VersionTable {
|
|||||||
private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Versions";
|
private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Versions";
|
||||||
|
|
||||||
private static final String COLUMN_FEATURE = "feature";
|
private static final String COLUMN_FEATURE = "feature";
|
||||||
|
private static final String COLUMN_INSTANCE_UID = "instance_uid";
|
||||||
private static final String COLUMN_VERSION = "version";
|
private static final String COLUMN_VERSION = "version";
|
||||||
|
|
||||||
private static final String WHERE_FEATURE_EQUALS = COLUMN_FEATURE + " = ?";
|
private static final String WHERE_FEATURE_AND_INSTANCE_UID_EQUALS =
|
||||||
|
COLUMN_FEATURE + " = ? AND " + COLUMN_INSTANCE_UID + " = ?";
|
||||||
|
|
||||||
|
private static final String PRIMARY_KEY =
|
||||||
|
"PRIMARY KEY (" + COLUMN_FEATURE + ", " + COLUMN_INSTANCE_UID + ")";
|
||||||
private static final String SQL_CREATE_TABLE_IF_NOT_EXISTS =
|
private static final String SQL_CREATE_TABLE_IF_NOT_EXISTS =
|
||||||
"CREATE TABLE IF NOT EXISTS "
|
"CREATE TABLE IF NOT EXISTS "
|
||||||
+ TABLE_NAME
|
+ TABLE_NAME
|
||||||
+ " ("
|
+ " ("
|
||||||
+ COLUMN_FEATURE
|
+ COLUMN_FEATURE
|
||||||
+ " INTEGER PRIMARY KEY NOT NULL,"
|
+ " INTEGER NOT NULL,"
|
||||||
|
+ COLUMN_INSTANCE_UID
|
||||||
|
+ " TEXT NOT NULL,"
|
||||||
+ COLUMN_VERSION
|
+ COLUMN_VERSION
|
||||||
+ " INTEGER NOT NULL)";
|
+ " INTEGER NOT NULL,"
|
||||||
|
+ PRIMARY_KEY
|
||||||
|
+ ")";
|
||||||
|
|
||||||
@Documented
|
@Documented
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@ -64,42 +72,51 @@ public final class VersionTable {
|
|||||||
private VersionTable() {}
|
private VersionTable() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the version of the specified feature.
|
* Sets the version of a specified instance of a specified feature.
|
||||||
*
|
*
|
||||||
* @param writableDatabase The database to update.
|
* @param writableDatabase The database to update.
|
||||||
* @param feature The feature.
|
* @param feature The feature.
|
||||||
|
* @param instanceUid The unique identifier of the instance of the feature.
|
||||||
* @param version The version.
|
* @param version The version.
|
||||||
*/
|
*/
|
||||||
public static void setVersion(
|
public static void setVersion(
|
||||||
SQLiteDatabase writableDatabase, @Feature int feature, int version) {
|
SQLiteDatabase writableDatabase, @Feature int feature, String instanceUid, int version) {
|
||||||
writableDatabase.execSQL(SQL_CREATE_TABLE_IF_NOT_EXISTS);
|
writableDatabase.execSQL(SQL_CREATE_TABLE_IF_NOT_EXISTS);
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(COLUMN_FEATURE, feature);
|
values.put(COLUMN_FEATURE, feature);
|
||||||
|
values.put(COLUMN_INSTANCE_UID, instanceUid);
|
||||||
values.put(COLUMN_VERSION, version);
|
values.put(COLUMN_VERSION, version);
|
||||||
writableDatabase.replace(TABLE_NAME, /* nullColumnHack= */ null, values);
|
writableDatabase.replace(TABLE_NAME, /* nullColumnHack= */ null, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the version of the specified feature.
|
* Removes the version of a specified instance of a feature.
|
||||||
*
|
*
|
||||||
* @param writableDatabase The database to update.
|
* @param writableDatabase The database to update.
|
||||||
* @param feature The feature.
|
* @param feature The feature.
|
||||||
|
* @param instanceUid The unique identifier of the instance of the feature.
|
||||||
*/
|
*/
|
||||||
public static void removeVersion(SQLiteDatabase writableDatabase, @Feature int feature) {
|
public static void removeVersion(
|
||||||
|
SQLiteDatabase writableDatabase, @Feature int feature, String instanceUid) {
|
||||||
if (!tableExists(writableDatabase, TABLE_NAME)) {
|
if (!tableExists(writableDatabase, TABLE_NAME)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
writableDatabase.delete(TABLE_NAME, WHERE_FEATURE_EQUALS, featureArgument(feature));
|
writableDatabase.delete(
|
||||||
|
TABLE_NAME,
|
||||||
|
WHERE_FEATURE_AND_INSTANCE_UID_EQUALS,
|
||||||
|
featureAndInstanceUidArguments(feature, instanceUid));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the version of the specified feature, or {@link #VERSION_UNSET} if no version
|
* Returns the version of a specified instance of a feature, or {@link #VERSION_UNSET} if no
|
||||||
* information is available.
|
* version is set.
|
||||||
*
|
*
|
||||||
* @param database The database to query.
|
* @param database The database to query.
|
||||||
* @param feature The feature.
|
* @param feature The feature.
|
||||||
|
* @param instanceUid The unique identifier of the instance of the feature.
|
||||||
|
* @return The version, or {@link #VERSION_UNSET} if no version is set.
|
||||||
*/
|
*/
|
||||||
public static int getVersion(SQLiteDatabase database, @Feature int feature) {
|
public static int getVersion(SQLiteDatabase database, @Feature int feature, String instanceUid) {
|
||||||
if (!tableExists(database, TABLE_NAME)) {
|
if (!tableExists(database, TABLE_NAME)) {
|
||||||
return VERSION_UNSET;
|
return VERSION_UNSET;
|
||||||
}
|
}
|
||||||
@ -107,8 +124,8 @@ public final class VersionTable {
|
|||||||
database.query(
|
database.query(
|
||||||
TABLE_NAME,
|
TABLE_NAME,
|
||||||
new String[] {COLUMN_VERSION},
|
new String[] {COLUMN_VERSION},
|
||||||
WHERE_FEATURE_EQUALS,
|
WHERE_FEATURE_AND_INSTANCE_UID_EQUALS,
|
||||||
featureArgument(feature),
|
featureAndInstanceUidArguments(feature, instanceUid),
|
||||||
/* groupBy= */ null,
|
/* groupBy= */ null,
|
||||||
/* having= */ null,
|
/* having= */ null,
|
||||||
/* orderBy= */ null)) {
|
/* orderBy= */ null)) {
|
||||||
@ -128,7 +145,7 @@ public final class VersionTable {
|
|||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] featureArgument(int feature) {
|
private static String[] featureAndInstanceUidArguments(int feature, String instance) {
|
||||||
return new String[] {Integer.toString(feature)};
|
return new String[] {Integer.toString(feature), instance};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ public final class DefaultDownloadIndex implements DownloadIndex {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
/* package */ static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Downloads";
|
/* package */ static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Downloads";
|
||||||
|
|
||||||
|
// TODO: Support multiple instances. Probably using the underlying cache UID.
|
||||||
|
@VisibleForTesting /* package */ static final String INSTANCE_UID = "singleton";
|
||||||
@VisibleForTesting /* package */ static final int TABLE_VERSION = 1;
|
@VisibleForTesting /* package */ static final int TABLE_VERSION = 1;
|
||||||
|
|
||||||
private static final String COLUMN_ID = "id";
|
private static final String COLUMN_ID = "id";
|
||||||
@ -218,12 +220,14 @@ public final class DefaultDownloadIndex implements DownloadIndex {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase();
|
SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase();
|
||||||
int version = VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE);
|
int version =
|
||||||
|
VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID);
|
||||||
if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) {
|
if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) {
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
writableDatabase.beginTransaction();
|
writableDatabase.beginTransaction();
|
||||||
try {
|
try {
|
||||||
VersionTable.setVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, TABLE_VERSION);
|
VersionTable.setVersion(
|
||||||
|
writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID, TABLE_VERSION);
|
||||||
writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS);
|
writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS);
|
||||||
writableDatabase.execSQL(SQL_CREATE_TABLE);
|
writableDatabase.execSQL(SQL_CREATE_TABLE);
|
||||||
writableDatabase.setTransactionSuccessful();
|
writableDatabase.setTransactionSuccessful();
|
||||||
|
@ -20,14 +20,16 @@ import android.database.Cursor;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import com.google.android.exoplayer2.database.DatabaseProvider;
|
import com.google.android.exoplayer2.database.DatabaseProvider;
|
||||||
import com.google.android.exoplayer2.database.VersionTable;
|
import com.google.android.exoplayer2.database.VersionTable;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/** Maintains an index of cache file metadata. */
|
/** Maintains an index of cache file metadata. */
|
||||||
/* package */ final class CacheFileMetadataIndex {
|
/* package */ final class CacheFileMetadataIndex {
|
||||||
|
|
||||||
private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "CacheFileMetadata";
|
private static final String TABLE_PREFIX = DatabaseProvider.TABLE_PREFIX + "CacheFileMetadata";
|
||||||
private static final int TABLE_VERSION = 1;
|
private static final int TABLE_VERSION = 1;
|
||||||
|
|
||||||
private static final String COLUMN_NAME = "name";
|
private static final String COLUMN_NAME = "name";
|
||||||
@ -44,12 +46,8 @@ import java.util.Set;
|
|||||||
new String[] {
|
new String[] {
|
||||||
COLUMN_NAME, COLUMN_LENGTH, COLUMN_LAST_ACCESS_TIMESTAMP,
|
COLUMN_NAME, COLUMN_LENGTH, COLUMN_LAST_ACCESS_TIMESTAMP,
|
||||||
};
|
};
|
||||||
|
private static final String TABLE_SCHEMA =
|
||||||
private static final String SQL_DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS " + TABLE_NAME;
|
"("
|
||||||
private static final String SQL_CREATE_TABLE =
|
|
||||||
"CREATE TABLE "
|
|
||||||
+ TABLE_NAME
|
|
||||||
+ " ("
|
|
||||||
+ COLUMN_NAME
|
+ COLUMN_NAME
|
||||||
+ " TEXT PRIMARY KEY NOT NULL,"
|
+ " TEXT PRIMARY KEY NOT NULL,"
|
||||||
+ COLUMN_LENGTH
|
+ COLUMN_LENGTH
|
||||||
@ -59,18 +57,42 @@ import java.util.Set;
|
|||||||
|
|
||||||
private final DatabaseProvider databaseProvider;
|
private final DatabaseProvider databaseProvider;
|
||||||
|
|
||||||
private boolean initialized;
|
@MonotonicNonNull private String tableName;
|
||||||
|
|
||||||
public CacheFileMetadataIndex(DatabaseProvider databaseProvider) {
|
public CacheFileMetadataIndex(DatabaseProvider databaseProvider) {
|
||||||
this.databaseProvider = databaseProvider;
|
this.databaseProvider = databaseProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Initializes the index for the given cache UID. */
|
||||||
|
public void initialize(long uid) {
|
||||||
|
String hexUid = Long.toHexString(uid);
|
||||||
|
tableName = TABLE_PREFIX + hexUid;
|
||||||
|
SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase();
|
||||||
|
int version =
|
||||||
|
VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_CACHE_FILE_METADATA, hexUid);
|
||||||
|
if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) {
|
||||||
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
|
writableDatabase.beginTransaction();
|
||||||
|
try {
|
||||||
|
VersionTable.setVersion(
|
||||||
|
writableDatabase, VersionTable.FEATURE_CACHE_FILE_METADATA, hexUid, TABLE_VERSION);
|
||||||
|
writableDatabase.execSQL("DROP TABLE IF EXISTS " + tableName);
|
||||||
|
writableDatabase.execSQL("CREATE TABLE " + tableName + " " + TABLE_SCHEMA);
|
||||||
|
writableDatabase.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
writableDatabase.endTransaction();
|
||||||
|
}
|
||||||
|
} else if (version < TABLE_VERSION) {
|
||||||
|
// There is no previous version currently.
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all file metadata keyed by file name. The returned map is mutable and may be modified
|
* Returns all file metadata keyed by file name. The returned map is mutable and may be modified
|
||||||
* by the caller.
|
* by the caller.
|
||||||
*/
|
*/
|
||||||
public Map<String, CacheFileMetadata> getAll() {
|
public Map<String, CacheFileMetadata> getAll() {
|
||||||
ensureInitialized();
|
|
||||||
try (Cursor cursor = getCursor()) {
|
try (Cursor cursor = getCursor()) {
|
||||||
Map<String, CacheFileMetadata> fileMetadata = new HashMap<>(cursor.getCount());
|
Map<String, CacheFileMetadata> fileMetadata = new HashMap<>(cursor.getCount());
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
@ -91,13 +113,13 @@ import java.util.Set;
|
|||||||
* @param lastAccessTimestamp The file last access timestamp.
|
* @param lastAccessTimestamp The file last access timestamp.
|
||||||
*/
|
*/
|
||||||
public void set(String name, long length, long lastAccessTimestamp) {
|
public void set(String name, long length, long lastAccessTimestamp) {
|
||||||
ensureInitialized();
|
Assertions.checkNotNull(tableName);
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(COLUMN_NAME, name);
|
values.put(COLUMN_NAME, name);
|
||||||
values.put(COLUMN_LENGTH, length);
|
values.put(COLUMN_LENGTH, length);
|
||||||
values.put(COLUMN_LAST_ACCESS_TIMESTAMP, lastAccessTimestamp);
|
values.put(COLUMN_LAST_ACCESS_TIMESTAMP, lastAccessTimestamp);
|
||||||
writableDatabase.replace(TABLE_NAME, /* nullColumnHack= */ null, values);
|
writableDatabase.replace(tableName, /* nullColumnHack= */ null, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,9 +128,9 @@ import java.util.Set;
|
|||||||
* @param name The name of the file whose metadata is to be removed.
|
* @param name The name of the file whose metadata is to be removed.
|
||||||
*/
|
*/
|
||||||
public void remove(String name) {
|
public void remove(String name) {
|
||||||
ensureInitialized();
|
Assertions.checkNotNull(tableName);
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
writableDatabase.delete(TABLE_NAME, WHERE_NAME_EQUALS, new String[] {name});
|
writableDatabase.delete(tableName, WHERE_NAME_EQUALS, new String[] {name});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,12 +139,12 @@ import java.util.Set;
|
|||||||
* @param names The names of the files whose metadata is to be removed.
|
* @param names The names of the files whose metadata is to be removed.
|
||||||
*/
|
*/
|
||||||
public void removeAll(Set<String> names) {
|
public void removeAll(Set<String> names) {
|
||||||
ensureInitialized();
|
Assertions.checkNotNull(tableName);
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
writableDatabase.beginTransaction();
|
writableDatabase.beginTransaction();
|
||||||
try {
|
try {
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
writableDatabase.delete(TABLE_NAME, WHERE_NAME_EQUALS, new String[] {name});
|
writableDatabase.delete(tableName, WHERE_NAME_EQUALS, new String[] {name});
|
||||||
}
|
}
|
||||||
writableDatabase.setTransactionSuccessful();
|
writableDatabase.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
@ -130,37 +152,12 @@ import java.util.Set;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureInitialized() {
|
|
||||||
if (initialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase();
|
|
||||||
int version =
|
|
||||||
VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_CACHE_FILE_METADATA);
|
|
||||||
if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) {
|
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
|
||||||
writableDatabase.beginTransaction();
|
|
||||||
try {
|
|
||||||
VersionTable.setVersion(
|
|
||||||
writableDatabase, VersionTable.FEATURE_CACHE_FILE_METADATA, TABLE_VERSION);
|
|
||||||
writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS);
|
|
||||||
writableDatabase.execSQL(SQL_CREATE_TABLE);
|
|
||||||
writableDatabase.setTransactionSuccessful();
|
|
||||||
} finally {
|
|
||||||
writableDatabase.endTransaction();
|
|
||||||
}
|
|
||||||
} else if (version < TABLE_VERSION) {
|
|
||||||
// There is no previous version currently.
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Cursor getCursor() {
|
private Cursor getCursor() {
|
||||||
|
Assertions.checkNotNull(tableName);
|
||||||
return databaseProvider
|
return databaseProvider
|
||||||
.getReadableDatabase()
|
.getReadableDatabase()
|
||||||
.query(
|
.query(
|
||||||
TABLE_NAME,
|
tableName,
|
||||||
COLUMNS,
|
COLUMNS,
|
||||||
/* selection */ null,
|
/* selection */ null,
|
||||||
/* selectionArgs= */ null,
|
/* selectionArgs= */ null,
|
||||||
|
@ -159,8 +159,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Loads the index file. */
|
/**
|
||||||
public void load() {
|
* Loads the index file for the given cache UID.
|
||||||
|
*
|
||||||
|
* @param uid The UID of the cache whose index is to be loaded.
|
||||||
|
*/
|
||||||
|
public void initialize(long uid) {
|
||||||
|
storage.initialize(uid);
|
||||||
|
if (previousStorage != null) {
|
||||||
|
previousStorage.initialize(uid);
|
||||||
|
}
|
||||||
if (!storage.exists() && previousStorage != null && previousStorage.exists()) {
|
if (!storage.exists() && previousStorage != null && previousStorage.exists()) {
|
||||||
// Copy from previous storage into current storage.
|
// Copy from previous storage into current storage.
|
||||||
loadFrom(previousStorage);
|
loadFrom(previousStorage);
|
||||||
@ -383,6 +391,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
/** Interface for the persistent index. */
|
/** Interface for the persistent index. */
|
||||||
private interface Storage {
|
private interface Storage {
|
||||||
|
|
||||||
|
/** Initializes the storage for the given cache UID. */
|
||||||
|
void initialize(long uid);
|
||||||
|
|
||||||
/** Returns whether the persisted index exists. */
|
/** Returns whether the persisted index exists. */
|
||||||
boolean exists();
|
boolean exists();
|
||||||
|
|
||||||
@ -409,9 +420,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
void storeFully(HashMap<String, CachedContent> content) throws CacheException;
|
void storeFully(HashMap<String, CachedContent> content) throws CacheException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures incremental changes to the index since the last {@link #load()} or {@link
|
* Ensures incremental changes to the index since the initial {@link #initialize(long)} or last
|
||||||
* #storeFully(HashMap)} are persisted. The storage will have been notified of all such changes
|
* {@link #storeFully(HashMap)} are persisted. The storage will have been notified of all such
|
||||||
* via {@link #onUpdate(CachedContent)} and {@link #onRemove(CachedContent)}.
|
* changes via {@link #onUpdate(CachedContent)} and {@link #onRemove(CachedContent)}.
|
||||||
*
|
*
|
||||||
* @param content The key to content map to persist.
|
* @param content The key to content map to persist.
|
||||||
* @throws CacheException If an error occurs persisting the index.
|
* @throws CacheException If an error occurs persisting the index.
|
||||||
@ -457,7 +468,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
throw new IllegalStateException(e); // Should never happen.
|
throw new IllegalStateException(e); // Should never happen.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Assertions.checkState(!encrypt);
|
Assertions.checkArgument(!encrypt);
|
||||||
}
|
}
|
||||||
this.encrypt = encrypt;
|
this.encrypt = encrypt;
|
||||||
this.cipher = cipher;
|
this.cipher = cipher;
|
||||||
@ -466,6 +477,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
atomicFile = new AtomicFile(file);
|
atomicFile = new AtomicFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(long uid) {
|
||||||
|
// Do nothing. Legacy storage uses a separate file for each cache.
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exists() {
|
public boolean exists() {
|
||||||
return atomicFile.exists();
|
return atomicFile.exists();
|
||||||
@ -665,7 +681,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
/** {@link Storage} implementation that uses an SQL database. */
|
/** {@link Storage} implementation that uses an SQL database. */
|
||||||
private static final class DatabaseStorage implements Storage {
|
private static final class DatabaseStorage implements Storage {
|
||||||
|
|
||||||
private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "CacheContentMetadata";
|
private static final String TABLE_PREFIX = DatabaseProvider.TABLE_PREFIX + "CacheIndex";
|
||||||
private static final int TABLE_VERSION = 1;
|
private static final int TABLE_VERSION = 1;
|
||||||
|
|
||||||
private static final String COLUMN_ID = "id";
|
private static final String COLUMN_ID = "id";
|
||||||
@ -679,12 +695,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
private static final String WHERE_ID_EQUALS = COLUMN_ID + " = ?";
|
private static final String WHERE_ID_EQUALS = COLUMN_ID + " = ?";
|
||||||
|
|
||||||
private static final String[] COLUMNS = new String[] {COLUMN_ID, COLUMN_KEY, COLUMN_METADATA};
|
private static final String[] COLUMNS = new String[] {COLUMN_ID, COLUMN_KEY, COLUMN_METADATA};
|
||||||
|
private static final String TABLE_SCHEMA =
|
||||||
private static final String SQL_DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS " + TABLE_NAME;
|
"("
|
||||||
private static final String SQL_CREATE_TABLE =
|
|
||||||
"CREATE TABLE "
|
|
||||||
+ TABLE_NAME
|
|
||||||
+ " ("
|
|
||||||
+ COLUMN_ID
|
+ COLUMN_ID
|
||||||
+ " INTEGER PRIMARY KEY NOT NULL,"
|
+ " INTEGER PRIMARY KEY NOT NULL,"
|
||||||
+ COLUMN_KEY
|
+ COLUMN_KEY
|
||||||
@ -695,15 +707,26 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
private final DatabaseProvider databaseProvider;
|
private final DatabaseProvider databaseProvider;
|
||||||
private final SparseArray<CachedContent> pendingUpdates;
|
private final SparseArray<CachedContent> pendingUpdates;
|
||||||
|
|
||||||
|
private String hexUid;
|
||||||
|
private String tableName;
|
||||||
|
|
||||||
public DatabaseStorage(DatabaseProvider databaseProvider) {
|
public DatabaseStorage(DatabaseProvider databaseProvider) {
|
||||||
this.databaseProvider = databaseProvider;
|
this.databaseProvider = databaseProvider;
|
||||||
pendingUpdates = new SparseArray<>();
|
pendingUpdates = new SparseArray<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(long uid) {
|
||||||
|
hexUid = Long.toHexString(uid);
|
||||||
|
tableName = TABLE_PREFIX + hexUid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exists() {
|
public boolean exists() {
|
||||||
return VersionTable.getVersion(
|
return VersionTable.getVersion(
|
||||||
databaseProvider.getReadableDatabase(), VersionTable.FEATURE_CACHE_CONTENT_METADATA)
|
databaseProvider.getReadableDatabase(),
|
||||||
|
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
||||||
|
hexUid)
|
||||||
!= VersionTable.VERSION_UNSET;
|
!= VersionTable.VERSION_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,8 +735,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
writableDatabase.beginTransaction();
|
writableDatabase.beginTransaction();
|
||||||
try {
|
try {
|
||||||
VersionTable.removeVersion(writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA);
|
VersionTable.removeVersion(
|
||||||
writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS);
|
writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA, hexUid);
|
||||||
|
dropTable(writableDatabase);
|
||||||
writableDatabase.setTransactionSuccessful();
|
writableDatabase.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
writableDatabase.endTransaction();
|
writableDatabase.endTransaction();
|
||||||
@ -728,7 +752,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
int version =
|
int version =
|
||||||
VersionTable.getVersion(
|
VersionTable.getVersion(
|
||||||
databaseProvider.getReadableDatabase(),
|
databaseProvider.getReadableDatabase(),
|
||||||
VersionTable.FEATURE_CACHE_CONTENT_METADATA);
|
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
||||||
|
hexUid);
|
||||||
if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) {
|
if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) {
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
writableDatabase.beginTransaction();
|
writableDatabase.beginTransaction();
|
||||||
@ -821,7 +846,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
return databaseProvider
|
return databaseProvider
|
||||||
.getReadableDatabase()
|
.getReadableDatabase()
|
||||||
.query(
|
.query(
|
||||||
TABLE_NAME,
|
tableName,
|
||||||
COLUMNS,
|
COLUMNS,
|
||||||
/* selection= */ null,
|
/* selection= */ null,
|
||||||
/* selectionArgs= */ null,
|
/* selectionArgs= */ null,
|
||||||
@ -832,13 +857,17 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
|
|
||||||
private void initializeTable(SQLiteDatabase writableDatabase) {
|
private void initializeTable(SQLiteDatabase writableDatabase) {
|
||||||
VersionTable.setVersion(
|
VersionTable.setVersion(
|
||||||
writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA, TABLE_VERSION);
|
writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA, hexUid, TABLE_VERSION);
|
||||||
writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS);
|
dropTable(writableDatabase);
|
||||||
writableDatabase.execSQL(SQL_CREATE_TABLE);
|
writableDatabase.execSQL("CREATE TABLE " + tableName + " " + TABLE_SCHEMA);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dropTable(SQLiteDatabase writableDatabase) {
|
||||||
|
writableDatabase.execSQL("DROP TABLE IF EXISTS " + tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteRow(SQLiteDatabase writableDatabase, int key) {
|
private void deleteRow(SQLiteDatabase writableDatabase, int key) {
|
||||||
writableDatabase.delete(TABLE_NAME, WHERE_ID_EQUALS, new String[] {Integer.toString(key)});
|
writableDatabase.delete(tableName, WHERE_ID_EQUALS, new String[] {Integer.toString(key)});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addOrUpdateRow(SQLiteDatabase writableDatabase, CachedContent cachedContent)
|
private void addOrUpdateRow(SQLiteDatabase writableDatabase, CachedContent cachedContent)
|
||||||
@ -851,7 +880,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
values.put(COLUMN_ID, cachedContent.id);
|
values.put(COLUMN_ID, cachedContent.id);
|
||||||
values.put(COLUMN_KEY, cachedContent.key);
|
values.put(COLUMN_KEY, cachedContent.key);
|
||||||
values.put(COLUMN_METADATA, data);
|
values.put(COLUMN_METADATA, data);
|
||||||
writableDatabase.replace(TABLE_NAME, /* nullColumnHack= */ null, values);
|
writableDatabase.replace(tableName, /* nullColumnHack= */ null, values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,8 +254,8 @@ public final class SimpleCache implements Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized @Nullable SimpleCacheSpan startReadWriteNonBlocking(String key, long position)
|
public synchronized @Nullable SimpleCacheSpan startReadWriteNonBlocking(
|
||||||
throws CacheException {
|
String key, long position) {
|
||||||
Assertions.checkState(!released);
|
Assertions.checkState(!released);
|
||||||
SimpleCacheSpan span = getSpan(key, position);
|
SimpleCacheSpan span = getSpan(key, position);
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ public final class SimpleCache implements Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized File startFile(String key, long position, long length) throws CacheException {
|
public synchronized File startFile(String key, long position, long length) {
|
||||||
Assertions.checkState(!released);
|
Assertions.checkState(!released);
|
||||||
CachedContent cachedContent = contentIndex.get(key);
|
CachedContent cachedContent = contentIndex.get(key);
|
||||||
Assertions.checkNotNull(cachedContent);
|
Assertions.checkNotNull(cachedContent);
|
||||||
@ -399,7 +399,7 @@ public final class SimpleCache implements Cache {
|
|||||||
* @param position The position of the span being requested.
|
* @param position The position of the span being requested.
|
||||||
* @return The corresponding cache {@link SimpleCacheSpan}.
|
* @return The corresponding cache {@link SimpleCacheSpan}.
|
||||||
*/
|
*/
|
||||||
private SimpleCacheSpan getSpan(String key, long position) throws CacheException {
|
private SimpleCacheSpan getSpan(String key, long position) {
|
||||||
CachedContent cachedContent = contentIndex.get(key);
|
CachedContent cachedContent = contentIndex.get(key);
|
||||||
if (cachedContent == null) {
|
if (cachedContent == null) {
|
||||||
return SimpleCacheSpan.createOpenHole(key, position);
|
return SimpleCacheSpan.createOpenHole(key, position);
|
||||||
@ -432,9 +432,9 @@ public final class SimpleCache implements Cache {
|
|||||||
// TODO: Decide how to handle this.
|
// TODO: Decide how to handle this.
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Pass the UID to the index, and use it.
|
contentIndex.initialize(uid);
|
||||||
contentIndex.load();
|
|
||||||
if (fileIndex != null) {
|
if (fileIndex != null) {
|
||||||
|
fileIndex.initialize(uid);
|
||||||
Map<String, CacheFileMetadata> fileMetadata = fileIndex.getAll();
|
Map<String, CacheFileMetadata> fileMetadata = fileIndex.getAll();
|
||||||
loadDirectory(cacheDir, /* isRoot= */ true, files, fileMetadata);
|
loadDirectory(cacheDir, /* isRoot= */ true, files, fileMetadata);
|
||||||
fileIndex.removeAll(fileMetadata.keySet());
|
fileIndex.removeAll(fileMetadata.keySet());
|
||||||
|
@ -15,77 +15,86 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.database;
|
package com.google.android.exoplayer2.database;
|
||||||
|
|
||||||
import static com.google.android.exoplayer2.database.VersionTable.FEATURE_CACHE_CONTENT_METADATA;
|
|
||||||
import static com.google.android.exoplayer2.database.VersionTable.FEATURE_OFFLINE;
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import org.junit.After;
|
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
|
||||||
|
|
||||||
/** Unit tests for {@link VersionTable}. */
|
/** Unit tests for {@link VersionTable}. */
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class VersionTableTest {
|
public class VersionTableTest {
|
||||||
|
|
||||||
private ExoDatabaseProvider databaseProvider;
|
private static final int FEATURE_1 = 1;
|
||||||
private SQLiteDatabase readableDatabase;
|
private static final int FEATURE_2 = 2;
|
||||||
private SQLiteDatabase writableDatabase;
|
private static final String INSTANCE_1 = "1";
|
||||||
|
private static final String INSTANCE_2 = "2";
|
||||||
|
|
||||||
|
private DatabaseProvider databaseProvider;
|
||||||
|
private SQLiteDatabase database;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
databaseProvider = new ExoDatabaseProvider(RuntimeEnvironment.application);
|
databaseProvider = TestUtil.getTestDatabaseProvider();
|
||||||
readableDatabase = databaseProvider.getReadableDatabase();
|
database = databaseProvider.getWritableDatabase();
|
||||||
writableDatabase = databaseProvider.getWritableDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
databaseProvider.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getVersion_nonExistingTable_returnsVersionUnset() {
|
public void getVersion_unsetFeature_returnsVersionUnset() {
|
||||||
int version = VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE);
|
int version = VersionTable.getVersion(database, FEATURE_1, INSTANCE_1);
|
||||||
|
assertThat(version).isEqualTo(VersionTable.VERSION_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getVersion_unsetVersion_returnsVersionUnset() {
|
||||||
|
VersionTable.setVersion(database, FEATURE_1, INSTANCE_1, 1);
|
||||||
|
int version = VersionTable.getVersion(database, FEATURE_1, INSTANCE_2);
|
||||||
assertThat(version).isEqualTo(VersionTable.VERSION_UNSET);
|
assertThat(version).isEqualTo(VersionTable.VERSION_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getVersion_returnsSetVersion() {
|
public void getVersion_returnsSetVersion() {
|
||||||
VersionTable.setVersion(writableDatabase, FEATURE_OFFLINE, 1);
|
VersionTable.setVersion(database, FEATURE_1, INSTANCE_1, 1);
|
||||||
assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)).isEqualTo(1);
|
assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(1);
|
||||||
|
|
||||||
VersionTable.setVersion(writableDatabase, FEATURE_OFFLINE, 10);
|
VersionTable.setVersion(database, FEATURE_1, INSTANCE_1, 2);
|
||||||
assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)).isEqualTo(10);
|
assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(2);
|
||||||
|
|
||||||
VersionTable.setVersion(writableDatabase, FEATURE_CACHE_CONTENT_METADATA, 5);
|
VersionTable.setVersion(database, FEATURE_2, INSTANCE_1, 3);
|
||||||
assertThat(VersionTable.getVersion(readableDatabase, FEATURE_CACHE_CONTENT_METADATA))
|
assertThat(VersionTable.getVersion(database, FEATURE_2, INSTANCE_1)).isEqualTo(3);
|
||||||
.isEqualTo(5);
|
assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(2);
|
||||||
assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)).isEqualTo(10);
|
|
||||||
|
VersionTable.setVersion(database, FEATURE_2, INSTANCE_2, 4);
|
||||||
|
assertThat(VersionTable.getVersion(database, FEATURE_2, INSTANCE_2)).isEqualTo(4);
|
||||||
|
assertThat(VersionTable.getVersion(database, FEATURE_2, INSTANCE_1)).isEqualTo(3);
|
||||||
|
assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeVersion_removesSetVersion() {
|
public void removeVersion_removesSetVersion() {
|
||||||
VersionTable.setVersion(writableDatabase, FEATURE_OFFLINE, 1);
|
VersionTable.setVersion(database, FEATURE_1, INSTANCE_1, 1);
|
||||||
assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE)).isEqualTo(1);
|
VersionTable.setVersion(database, FEATURE_1, INSTANCE_2, 2);
|
||||||
|
assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1)).isEqualTo(1);
|
||||||
|
assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_2)).isEqualTo(2);
|
||||||
|
|
||||||
VersionTable.removeVersion(writableDatabase, FEATURE_OFFLINE);
|
VersionTable.removeVersion(database, FEATURE_1, INSTANCE_1);
|
||||||
assertThat(VersionTable.getVersion(readableDatabase, FEATURE_OFFLINE))
|
assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_1))
|
||||||
.isEqualTo(VersionTable.VERSION_UNSET);
|
.isEqualTo(VersionTable.VERSION_UNSET);
|
||||||
|
assertThat(VersionTable.getVersion(database, FEATURE_1, INSTANCE_2)).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doesTableExist_nonExistingTable_returnsFalse() {
|
public void doesTableExist_nonExistingTable_returnsFalse() {
|
||||||
assertThat(VersionTable.tableExists(readableDatabase, "NonExistingTable")).isFalse();
|
assertThat(VersionTable.tableExists(database, "NonExistingTable")).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doesTableExist_existingTable_returnsTrue() {
|
public void doesTableExist_existingTable_returnsTrue() {
|
||||||
String table = "TestTable";
|
String table = "TestTable";
|
||||||
databaseProvider.getWritableDatabase().execSQL("CREATE TABLE " + table + " (dummy INTEGER)");
|
databaseProvider.getWritableDatabase().execSQL("CREATE TABLE " + table + " (dummy INTEGER)");
|
||||||
assertThat(VersionTable.tableExists(readableDatabase, table)).isTrue();
|
assertThat(VersionTable.tableExists(database, table)).isTrue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.offline;
|
package com.google.android.exoplayer2.offline;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.offline.DefaultDownloadIndex.INSTANCE_UID;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
@ -180,12 +181,14 @@ public class DefaultDownloadIndexTest {
|
|||||||
@Test
|
@Test
|
||||||
public void putDownloadState_setsVersion() {
|
public void putDownloadState_setsVersion() {
|
||||||
SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase();
|
SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase();
|
||||||
assertThat(VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE))
|
assertThat(
|
||||||
|
VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID))
|
||||||
.isEqualTo(VersionTable.VERSION_UNSET);
|
.isEqualTo(VersionTable.VERSION_UNSET);
|
||||||
|
|
||||||
downloadIndex.putDownloadState(new DownloadStateBuilder("id1").build());
|
downloadIndex.putDownloadState(new DownloadStateBuilder("id1").build());
|
||||||
|
|
||||||
assertThat(VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE))
|
assertThat(
|
||||||
|
VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID))
|
||||||
.isEqualTo(DefaultDownloadIndex.TABLE_VERSION);
|
.isEqualTo(DefaultDownloadIndex.TABLE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,14 +201,16 @@ public class DefaultDownloadIndexTest {
|
|||||||
cursor.close();
|
cursor.close();
|
||||||
|
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
VersionTable.setVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, Integer.MAX_VALUE);
|
VersionTable.setVersion(
|
||||||
|
writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID, Integer.MAX_VALUE);
|
||||||
|
|
||||||
downloadIndex = new DefaultDownloadIndex(databaseProvider);
|
downloadIndex = new DefaultDownloadIndex(databaseProvider);
|
||||||
|
|
||||||
cursor = downloadIndex.getDownloadStates();
|
cursor = downloadIndex.getDownloadStates();
|
||||||
assertThat(cursor.getCount()).isEqualTo(0);
|
assertThat(cursor.getCount()).isEqualTo(0);
|
||||||
cursor.close();
|
cursor.close();
|
||||||
assertThat(VersionTable.getVersion(writableDatabase, VersionTable.FEATURE_OFFLINE))
|
assertThat(
|
||||||
|
VersionTable.getVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID))
|
||||||
.isEqualTo(DefaultDownloadIndex.TABLE_VERSION);
|
.isEqualTo(DefaultDownloadIndex.TABLE_VERSION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ public class CachedContentIndexTest {
|
|||||||
fos.write(testIndexV1File);
|
fos.write(testIndexV1File);
|
||||||
fos.close();
|
fos.close();
|
||||||
|
|
||||||
index.load();
|
index.initialize(/* uid= */ 0);
|
||||||
assertThat(index.getAll()).hasSize(2);
|
assertThat(index.getAll()).hasSize(2);
|
||||||
|
|
||||||
assertThat(index.assignIdForKey("ABCDE")).isEqualTo(5);
|
assertThat(index.assignIdForKey("ABCDE")).isEqualTo(5);
|
||||||
@ -181,7 +181,7 @@ public class CachedContentIndexTest {
|
|||||||
fos.write(testIndexV2File);
|
fos.write(testIndexV2File);
|
||||||
fos.close();
|
fos.close();
|
||||||
|
|
||||||
index.load();
|
index.initialize(/* uid= */ 0);
|
||||||
assertThat(index.getAll()).hasSize(2);
|
assertThat(index.getAll()).hasSize(2);
|
||||||
|
|
||||||
assertThat(index.assignIdForKey("ABCDE")).isEqualTo(5);
|
assertThat(index.assignIdForKey("ABCDE")).isEqualTo(5);
|
||||||
@ -325,7 +325,7 @@ public class CachedContentIndexTest {
|
|||||||
index.getOrAdd("ABCDE").applyMetadataMutations(mutations2);
|
index.getOrAdd("ABCDE").applyMetadataMutations(mutations2);
|
||||||
index.store();
|
index.store();
|
||||||
|
|
||||||
index2.load();
|
index2.initialize(/* uid= */ 0);
|
||||||
Set<String> keys = index.getKeys();
|
Set<String> keys = index.getKeys();
|
||||||
Set<String> keys2 = index2.getKeys();
|
Set<String> keys2 = index2.getKeys();
|
||||||
assertThat(keys2).isEqualTo(keys);
|
assertThat(keys2).isEqualTo(keys);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user