Commit 8b580a22 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media History] Add cached aggregate watchtime

Add the cached aggregate watchtime for audio+
video playbacks on the origin. We are planning
to use this for ranking so we need fast access.

BUG=1024351

Change-Id: I90e6dd4e162457cc6a6cf5c00593a6ca7f7d6581
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2036796
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#738726}
parent 04bf26d7
......@@ -30,7 +30,8 @@ sql::InitStatus MediaHistoryOriginTable::CreateTableIfNonExistent() {
"media_engagement_visits INTEGER,"
"media_engagement_playbacks INTEGER,"
"media_engagement_last_playback_time REAL,"
"media_engagement_has_high_score INTEGER)",
"media_engagement_has_high_score INTEGER, "
"aggregate_watchtime_audio_video_s INTEGER DEFAULT 0)",
kTableName)
.c_str());
......@@ -66,4 +67,34 @@ bool MediaHistoryOriginTable::CreateOriginId(const std::string& origin) {
return true;
}
bool MediaHistoryOriginTable::IncrementAggregateAudioVideoWatchTime(
const std::string& origin,
const base::TimeDelta& time) {
DCHECK_LT(0, DB()->transaction_nesting());
if (!CanAccessDatabase())
return false;
// Update the cached aggregate watchtime in the origin table.
sql::Statement statement(DB()->GetCachedStatement(
SQL_FROM_HERE,
base::StringPrintf("UPDATE %s SET "
"aggregate_watchtime_audio_video_s = "
"aggregate_watchtime_audio_video_s + ?, "
"last_updated_time_s = ? "
"WHERE origin = ?",
kTableName)
.c_str()));
statement.BindInt64(0, time.InSeconds());
statement.BindInt64(1,
base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds());
statement.BindString(2, origin);
if (!statement.Run()) {
LOG(ERROR) << "Failed to update the watchtime.";
return false;
}
return true;
}
} // namespace media_history
......@@ -28,6 +28,10 @@ class MediaHistoryOriginTable : public MediaHistoryTableBase {
// Returns a flag indicating whether the origin id was created successfully.
bool CreateOriginId(const std::string& origin);
// Returns a flag indicating whether watchtime was increased successfully.
bool IncrementAggregateAudioVideoWatchTime(const std::string& origin,
const base::TimeDelta& time);
DISALLOW_COPY_AND_ASSIGN(MediaHistoryOriginTable);
};
......
......@@ -119,12 +119,22 @@ void MediaHistoryStoreInternal::SavePlayback(
return;
}
if (CreateOriginId(watch_time.origin.spec()) &&
playback_table_->SavePlayback(watch_time)) {
DB()->CommitTransaction();
} else {
auto origin = watch_time.origin.spec();
if (!(CreateOriginId(origin) && playback_table_->SavePlayback(watch_time))) {
DB()->RollbackTransaction();
return;
}
if (watch_time.has_audio && watch_time.has_video) {
if (!origin_table_->IncrementAggregateAudioVideoWatchTime(
origin, watch_time.cumulative_watch_time)) {
DB()->RollbackTransaction();
return;
}
}
DB()->CommitTransaction();
}
void MediaHistoryStoreInternal::Initialize() {
......
......@@ -230,4 +230,92 @@ TEST_F(MediaHistoryStoreUnitTest, UrlShouldBeUniqueForSessions) {
}
}
TEST_F(MediaHistoryStoreUnitTest, SavePlayback_IncrementAggregateWatchtime) {
GURL url("http://google.com/test");
GURL url_alt("http://example.org/test");
{
// Record a watchtime for audio/video for 30 seconds.
content::MediaPlayerWatchTime watch_time(
url, url.GetOrigin(), base::TimeDelta::FromSeconds(30),
base::TimeDelta(), true /* has_video */, true /* has_audio */);
GetMediaHistoryStore()->SavePlayback(watch_time);
content::RunAllTasksUntilIdle();
}
{
// Record a watchtime for audio/video for 60 seconds.
content::MediaPlayerWatchTime watch_time(
url, url.GetOrigin(), base::TimeDelta::FromSeconds(60),
base::TimeDelta(), true /* has_video */, true /* has_audio */);
GetMediaHistoryStore()->SavePlayback(watch_time);
content::RunAllTasksUntilIdle();
}
{
// Record an audio-only watchtime for 30 seconds.
content::MediaPlayerWatchTime watch_time(
url, url.GetOrigin(), base::TimeDelta::FromSeconds(30),
base::TimeDelta(), false /* has_video */, true /* has_audio */);
GetMediaHistoryStore()->SavePlayback(watch_time);
content::RunAllTasksUntilIdle();
}
const int64_t url_now_in_seconds_before =
base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds();
{
// Record a video-only watchtime for 30 seconds.
content::MediaPlayerWatchTime watch_time(
url, url.GetOrigin(), base::TimeDelta::FromSeconds(30),
base::TimeDelta(), true /* has_video */, false /* has_audio */);
GetMediaHistoryStore()->SavePlayback(watch_time);
content::RunAllTasksUntilIdle();
}
const int64_t url_now_in_seconds_after =
base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds();
{
// Record a watchtime for audio/video for 60 seconds on a different origin.
content::MediaPlayerWatchTime watch_time(
url_alt, url_alt.GetOrigin(), base::TimeDelta::FromSeconds(30),
base::TimeDelta(), true /* has_video */, true /* has_audio */);
GetMediaHistoryStore()->SavePlayback(watch_time);
content::RunAllTasksUntilIdle();
}
const int64_t url_alt_now_in_seconds_after =
base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds();
{
// Check the playbacks were recorded.
mojom::MediaHistoryStatsPtr stats = GetStatsSync();
EXPECT_EQ(2, stats->table_row_counts[MediaHistoryOriginTable::kTableName]);
EXPECT_EQ(5,
stats->table_row_counts[MediaHistoryPlaybackTable::kTableName]);
}
// Verify that the origin table has the correct aggregate watchtime in
// minutes.
sql::Statement s(GetDB().GetUniqueStatement(
"SELECT origin, aggregate_watchtime_audio_video_s, last_updated_time_s "
"FROM origin"));
ASSERT_TRUE(s.is_valid());
EXPECT_TRUE(s.Step());
EXPECT_EQ("http://google.com/", s.ColumnString(0));
EXPECT_EQ(90, s.ColumnInt64(1));
EXPECT_LE(url_now_in_seconds_before, s.ColumnInt64(2));
EXPECT_GE(url_now_in_seconds_after, s.ColumnInt64(2));
EXPECT_TRUE(s.Step());
EXPECT_EQ("http://example.org/", s.ColumnString(0));
EXPECT_EQ(30, s.ColumnInt64(1));
EXPECT_LE(url_now_in_seconds_after, s.ColumnInt64(2));
EXPECT_GE(url_alt_now_in_seconds_after, s.ColumnInt64(2));
EXPECT_FALSE(s.Step());
}
} // namespace media_history
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment