Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redo caching in entries queries #592

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions classes/class-wpcom-liveblog-entry-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,74 @@ public function get_between_timestamps( $start_timestamp, $end_timestamp ) {
return $this->find_between_timestamps( $all_entries, $start_timestamp, $end_timestamp );
}

/**
* Get entries between two timestamps, using a Date Query.
*
* @param int $start_timestamp
* @param int $end_timestamp
* @return array
*/
public function get_between_timestamps_with_query( $start_timestamp, $end_timestamp ) {
$args = array(
'date_query' => array(
'after' => date( 'c' , $start_timestamp ),
'before' => date( 'c' , $end_timestamp ),
'inclusive' => true,
),
);

$entries = $this->get( $args );

return self::remove_replaced_entries( $entries );
}

/**
* Get the total number of entries for a Liveblog post
*
* The total entries is the count of _all_ entries, minus deletions
*
* Deletions are stored as regular comments, but with no content and a
* "replaces" meta value
*
* NOTE - currently updates are counted as entries, which is probably wrong
* and will throw off pagination, but this is designed to match the behavior
* in WPCOM_Liveblog::flatten_entries(), which is also used for pagination calculation
*
* @return int
*/
public function count_entries() {
$latest_timestamp = $this->get_latest_timestamp();

$cache_key = $this->key . '_entries_count_' . $this->post_id . '_' . $latest_timestamp;

$count = wp_cache_get( $cache_key, 'liveblog' );

if ( false !== $count ) {
return $count;
}

// Count all comments, excluding deletions
global $wpdb;

$count = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) as count FROM $wpdb->comments WHERE
comment_post_id = %d
AND comment_type = %s
AND comment_approved = %s
AND comment_content != %s",
$this->post_id,
$this->key,
$this->key,
''
)
);

wp_cache_set( $cache_key, $count, 'liveblog' );

return $count;
}

public function has_any() {
return (bool) $this->get();
}
Expand Down
93 changes: 93 additions & 0 deletions liveblog.php
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,99 @@ public static function get_entries_by_time( $start_timestamp, $end_timestamp ) {
return $result;
}

/**
* Get Liveblog entries between a start and end time for a post, with
* cached results.
*
* NOTE - get_entries_by_time() is also cached, but it uses a full list
* of all entries, via WPCOM_Liveblog_Entry_Query::get_all_entries_asc().
* That approach breaks down when there are more entries than can fit in
* a single cache key, so this function caches just the results
*
* This extra caching also bypasses both the additional processing
* required that happens inside $entry->for_json(), which is _always_ at least one db
* query (for the comment author user coming from get_comment_class()), and
* various the filters and processing performed there
*
* @param int $start_timestamp The start time boundary
* @param int $end_timestamp The end time boundary
*
* @return An array of Liveblog entries, possibly empty.
*/
public static function get_entries_by_time_cached( $start_timestamp, $end_timestamp ) {
// Set some defaults
$latest_timestamp = null;
$entries_for_json = array();

$now = time();

// If end timestamp is in future, set a cache TTL until it's not
// Must do this to match behavior of get_entries_by_time()
if ( $end_timestamp > $now ) {
self::$cache_control_max_age = $end_timestamp - $now;
}

if ( empty( self::$entry_query ) ) {
self::$entry_query = new WPCOM_Liveblog_Entry_Query( self::$post_id, self::KEY );
}

$latest_timestamp = self::$entry_query->get_latest_timestamp();

// If the requested timestamp is later than the latest comment timestamp,
// normalize it to the latest comment timestamp to get a higher hitrate
if ( $end_timestamp > $latest_timestamp ) {
$end_timestamp = $latest_timestamp;
}

$cache_key = self::KEY . '_result_' . self::$post_id . '_' . $start_timestamp . '_' . $end_timestamp;

// Were they cached already?
$cached_result = wp_cache_get( $cache_key, 'liveblog' );

if ( false !== $cached_result ) {
return $cached_result;
}

// Get liveblog entries within the start and end boundaries
$entries = self::$entry_query->get_between_timestamps_with_query( $start_timestamp, $end_timestamp );

$pages = false;
$per_page = WPCOM_Liveblog_Lazyloader::get_number_of_entries();

if ( ! empty( $entries ) ) {
$entries_count = self::$entry_query->count_entries();

/**
* Loop through each liveblog entry, set the most recent timestamp, and
* put the JSON data for each entry into a neat little array.
*/
foreach ( $entries as $entry ) {
$latest_timestamp = max( $latest_timestamp, $entry->get_timestamp() );
$entries_for_json[] = $entry->for_json();
}

$pages = ceil( $entries_count / $per_page );
}

// Create the result array
$result = array(
'entries' => $entries_for_json,
'latest_timestamp' => $latest_timestamp,
'refresh_interval' => self::get_refresh_interval(),
'pages' => $pages,
);

if ( ! empty( $entries_for_json ) ) {
do_action( 'liveblog_entry_request', $result );
} else {
do_action( 'liveblog_entry_request_empty' );
}

wp_cache_set( $cache_key, $result, 'liveblog' );

return $result;
}

/**
* Is a given post_id a liveblog enabled post?
*
Expand Down