Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
a6c1dbe1
authored
Feb 06, 2019
by
olly
Committed by
Oliver Woodman
Feb 06, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Implement CacheFileMetadataIndex using SQLite
PiperOrigin-RevId: 232670039
parent
7eed60c9
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
137 additions
and
24 deletions
library/core/src/main/java/com/google/android/exoplayer2/database/VersionTable.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheFileMetadataIndex.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java
library/core/src/test/java/com/google/android/exoplayer2/database/VersionTableTest.java
library/core/src/main/java/com/google/android/exoplayer2/database/VersionTable.java
View file @
a6c1dbe1
...
@@ -35,8 +35,10 @@ public final class VersionTable {
...
@@ -35,8 +35,10 @@ public final class VersionTable {
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
;
/** Version of tables used for cache functionality. */
/** Version of tables used for cache content metadata. */
public
static
final
int
FEATURE_CACHE
=
1
;
public
static
final
int
FEATURE_CACHE_CONTENT_METADATA
=
1
;
/** Version of tables used for cache file metadata. */
public
static
final
int
FEATURE_CACHE_FILE_METADATA
=
2
;
private
static
final
String
TABLE_NAME
=
DatabaseProvider
.
TABLE_PREFIX
+
"Versions"
;
private
static
final
String
TABLE_NAME
=
DatabaseProvider
.
TABLE_PREFIX
+
"Versions"
;
...
@@ -54,7 +56,7 @@ public final class VersionTable {
...
@@ -54,7 +56,7 @@ public final class VersionTable {
@Documented
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
({
FEATURE_OFFLINE
,
FEATURE_CACHE
})
@IntDef
({
FEATURE_OFFLINE
,
FEATURE_CACHE
_CONTENT_METADATA
,
FEATURE_CACHE_FILE_METADATA
})
private
@interface
Feature
{}
private
@interface
Feature
{}
private
VersionTable
()
{}
private
VersionTable
()
{}
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheFileMetadataIndex.java
View file @
a6c1dbe1
...
@@ -15,19 +15,72 @@
...
@@ -15,19 +15,72 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
upstream
.
cache
;
package
com
.
google
.
android
.
exoplayer2
.
upstream
.
cache
;
import
java.util.Collections
;
import
android.content.ContentValues
;
import
android.database.Cursor
;
import
android.database.sqlite.SQLiteDatabase
;
import
com.google.android.exoplayer2.database.DatabaseProvider
;
import
com.google.android.exoplayer2.database.VersionTable
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.Set
;
/** Maintains an index of cache file metadata. */
/** Maintains an index of cache file metadata. */
/* package */
class
CacheFileMetadataIndex
{
/* package */
final
class
CacheFileMetadataIndex
{
private
static
final
String
TABLE_NAME
=
DatabaseProvider
.
TABLE_PREFIX
+
"CacheFileMetadata"
;
private
static
final
int
TABLE_VERSION
=
1
;
private
static
final
String
COLUMN_NAME
=
"name"
;
private
static
final
String
COLUMN_LENGTH
=
"length"
;
private
static
final
String
COLUMN_LAST_ACCESS_TIMESTAMP
=
"last_access_timestamp"
;
private
static
final
int
COLUMN_INDEX_NAME
=
0
;
private
static
final
int
COLUMN_INDEX_LENGTH
=
1
;
private
static
final
int
COLUMN_INDEX_LAST_ACCESS_TIMESTAMP
=
2
;
private
static
final
String
WHERE_NAME_EQUALS
=
COLUMN_INDEX_NAME
+
" = ?"
;
private
static
final
String
[]
COLUMNS
=
new
String
[]
{
COLUMN_NAME
,
COLUMN_LENGTH
,
COLUMN_LAST_ACCESS_TIMESTAMP
,
};
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
+
" TEXT PRIMARY KEY NOT NULL,"
+
COLUMN_LENGTH
+
" INTEGER NOT NULL,"
+
COLUMN_LAST_ACCESS_TIMESTAMP
+
" INTEGER NOT NULL)"
;
private
final
DatabaseProvider
databaseProvider
;
private
boolean
initialized
;
public
CacheFileMetadataIndex
(
DatabaseProvider
databaseProvider
)
{
this
.
databaseProvider
=
databaseProvider
;
}
/**
/**
* 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
()
{
return
Collections
.
emptyMap
();
ensureInitialized
();
try
(
Cursor
cursor
=
getCursor
())
{
Map
<
String
,
CacheFileMetadata
>
fileMetadata
=
new
HashMap
<>(
cursor
.
getCount
());
while
(
cursor
.
moveToNext
())
{
String
name
=
cursor
.
getString
(
COLUMN_INDEX_NAME
);
long
length
=
cursor
.
getLong
(
COLUMN_INDEX_LENGTH
);
long
lastAccessTimestamp
=
cursor
.
getLong
(
COLUMN_INDEX_LAST_ACCESS_TIMESTAMP
);
fileMetadata
.
put
(
name
,
new
CacheFileMetadata
(
length
,
lastAccessTimestamp
));
}
return
fileMetadata
;
}
}
}
/**
/**
...
@@ -36,11 +89,15 @@ import java.util.Set;
...
@@ -36,11 +89,15 @@ import java.util.Set;
* @param name The name of the file.
* @param name The name of the file.
* @param length The file length.
* @param length The file length.
* @param lastAccessTimestamp The file last access timestamp.
* @param lastAccessTimestamp The file last access timestamp.
* @return Whether the index was updated successfully.
*/
*/
public
boolean
set
(
String
name
,
long
length
,
long
lastAccessTimestamp
)
{
public
void
set
(
String
name
,
long
length
,
long
lastAccessTimestamp
)
{
// TODO.
ensureInitialized
();
return
false
;
SQLiteDatabase
writableDatabase
=
databaseProvider
.
getWritableDatabase
();
ContentValues
values
=
new
ContentValues
();
values
.
put
(
COLUMN_NAME
,
name
);
values
.
put
(
COLUMN_LENGTH
,
length
);
values
.
put
(
COLUMN_LAST_ACCESS_TIMESTAMP
,
lastAccessTimestamp
);
writableDatabase
.
replace
(
TABLE_NAME
,
/* nullColumnHack= */
null
,
values
);
}
}
/**
/**
...
@@ -49,7 +106,9 @@ import java.util.Set;
...
@@ -49,7 +106,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
)
{
// TODO.
ensureInitialized
();
SQLiteDatabase
writableDatabase
=
databaseProvider
.
getWritableDatabase
();
writableDatabase
.
delete
(
TABLE_NAME
,
WHERE_NAME_EQUALS
,
new
String
[]
{
name
});
}
}
/**
/**
...
@@ -58,6 +117,55 @@ import java.util.Set;
...
@@ -58,6 +117,55 @@ 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
)
{
// TODO.
ensureInitialized
();
SQLiteDatabase
writableDatabase
=
databaseProvider
.
getWritableDatabase
();
writableDatabase
.
beginTransaction
();
try
{
for
(
String
name
:
names
)
{
writableDatabase
.
delete
(
TABLE_NAME
,
WHERE_NAME_EQUALS
,
new
String
[]
{
name
});
}
writableDatabase
.
setTransactionSuccessful
();
}
finally
{
writableDatabase
.
endTransaction
();
}
}
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
()
{
return
databaseProvider
.
getReadableDatabase
()
.
query
(
TABLE_NAME
,
COLUMNS
,
/* selection */
null
,
/* selectionArgs= */
null
,
/* groupBy= */
null
,
/* having= */
null
,
/* orderBy= */
null
);
}
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java
View file @
a6c1dbe1
...
@@ -678,7 +678,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -678,7 +678,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
// the entire table. Currently this implementation only encrypts new and updated entries.
// the entire table. Currently this implementation only encrypts new and updated entries.
private
static
final
class
SQLiteStorage
implements
Storage
{
private
static
final
class
SQLiteStorage
implements
Storage
{
private
static
final
String
TABLE_NAME
=
DatabaseProvider
.
TABLE_PREFIX
+
"Cache"
;
private
static
final
String
TABLE_NAME
=
DatabaseProvider
.
TABLE_PREFIX
+
"Cache
ContentMetadata
"
;
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"
;
...
@@ -736,7 +736,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -736,7 +736,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
public
boolean
exists
()
{
public
boolean
exists
()
{
return
file
.
exists
()
return
file
.
exists
()
&&
VersionTable
.
getVersion
(
&&
VersionTable
.
getVersion
(
databaseProvider
.
getReadableDatabase
(),
VersionTable
.
FEATURE_CACHE
)
databaseProvider
.
getReadableDatabase
(),
VersionTable
.
FEATURE_CACHE_CONTENT_METADATA
)
!=
VersionTable
.
VERSION_UNSET
;
!=
VersionTable
.
VERSION_UNSET
;
}
}
...
@@ -755,7 +756,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -755,7 +756,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
try
{
try
{
int
version
=
int
version
=
VersionTable
.
getVersion
(
VersionTable
.
getVersion
(
databaseProvider
.
getReadableDatabase
(),
VersionTable
.
FEATURE_CACHE
);
databaseProvider
.
getReadableDatabase
(),
VersionTable
.
FEATURE_CACHE_CONTENT_METADATA
);
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
();
...
@@ -870,7 +872,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -870,7 +872,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
}
}
private
void
initializeTable
(
SQLiteDatabase
writableDatabase
)
{
private
void
initializeTable
(
SQLiteDatabase
writableDatabase
)
{
VersionTable
.
setVersion
(
writableDatabase
,
VersionTable
.
FEATURE_CACHE
,
TABLE_VERSION
);
VersionTable
.
setVersion
(
writableDatabase
,
VersionTable
.
FEATURE_CACHE_CONTENT_METADATA
,
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
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java
View file @
a6c1dbe1
...
@@ -253,13 +253,12 @@ public final class SimpleCache implements Cache {
...
@@ -253,13 +253,12 @@ public final class SimpleCache implements Cache {
String
fileName
=
span
.
file
.
getName
();
String
fileName
=
span
.
file
.
getName
();
long
length
=
span
.
length
;
long
length
=
span
.
length
;
long
lastAccessTimestamp
=
System
.
currentTimeMillis
();
long
lastAccessTimestamp
=
System
.
currentTimeMillis
();
// Updating the file itself to incorporate the new last access timestamp is much slower than
boolean
updateFile
=
false
;
// updating the file index. Hence we only update the file if we don't have a file index, or if
// updating the file index failed.
boolean
updateFile
;
if
(
fileIndex
!=
null
)
{
if
(
fileIndex
!=
null
)
{
updateFile
=
!
fileIndex
.
set
(
fileName
,
length
,
lastAccessTimestamp
);
fileIndex
.
set
(
fileName
,
length
,
lastAccessTimestamp
);
}
else
{
}
else
{
// Updating the file itself to incorporate the new last access timestamp is much slower than
// updating the file index. Hence we only update the file if we don't have a file index.
updateFile
=
true
;
updateFile
=
true
;
}
}
SimpleCacheSpan
newSpan
=
SimpleCacheSpan
newSpan
=
...
...
library/core/src/test/java/com/google/android/exoplayer2/database/VersionTableTest.java
View file @
a6c1dbe1
...
@@ -15,7 +15,7 @@
...
@@ -15,7 +15,7 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
database
;
package
com
.
google
.
android
.
exoplayer2
.
database
;
import
static
com
.
google
.
android
.
exoplayer2
.
database
.
VersionTable
.
FEATURE_CACHE
;
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
.
android
.
exoplayer2
.
database
.
VersionTable
.
FEATURE_OFFLINE
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
...
@@ -61,8 +61,9 @@ public class VersionTableTest {
...
@@ -61,8 +61,9 @@ public class VersionTableTest {
VersionTable
.
setVersion
(
writableDatabase
,
FEATURE_OFFLINE
,
10
);
VersionTable
.
setVersion
(
writableDatabase
,
FEATURE_OFFLINE
,
10
);
assertThat
(
VersionTable
.
getVersion
(
readableDatabase
,
FEATURE_OFFLINE
)).
isEqualTo
(
10
);
assertThat
(
VersionTable
.
getVersion
(
readableDatabase
,
FEATURE_OFFLINE
)).
isEqualTo
(
10
);
VersionTable
.
setVersion
(
writableDatabase
,
FEATURE_CACHE
,
5
);
VersionTable
.
setVersion
(
writableDatabase
,
FEATURE_CACHE_CONTENT_METADATA
,
5
);
assertThat
(
VersionTable
.
getVersion
(
readableDatabase
,
FEATURE_CACHE
)).
isEqualTo
(
5
);
assertThat
(
VersionTable
.
getVersion
(
readableDatabase
,
FEATURE_CACHE_CONTENT_METADATA
))
.
isEqualTo
(
5
);
assertThat
(
VersionTable
.
getVersion
(
readableDatabase
,
FEATURE_OFFLINE
)).
isEqualTo
(
10
);
assertThat
(
VersionTable
.
getVersion
(
readableDatabase
,
FEATURE_OFFLINE
)).
isEqualTo
(
10
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment