Completed
Push — master-stable ( ed6d22...a9021a )
by
unknown
510:54 queued 499:45
created

Jetpack_Sync_Module_Full_Sync::reset_data()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 6
rs 9.4285
1
<?php
2
3
/**
4
 * This class does a full resync of the database by
5
 * enqueuing an outbound action for every single object
6
 * that we care about.
7
 *
8
 * This class, and its related class Jetpack_Sync_Module, contain a few non-obvious optimisations that should be explained:
9
 * - we fire an action called jetpack_full_sync_start so that WPCOM can erase the contents of the cached database
10
 * - for each object type, we page through the object IDs and enqueue them by firing some monitored actions
11
 * - we load the full objects for those IDs in chunks of Jetpack_Sync_Module::ARRAY_CHUNK_SIZE (to reduce the number of MySQL calls)
12
 * - we fire a trigger for the entire array which the Jetpack_Sync_Listener then serializes and queues.
13
 */
14
15
require_once 'class.jetpack-sync-wp-replicastore.php';
16
17
class Jetpack_Sync_Module_Full_Sync extends Jetpack_Sync_Module {
18
	const STATUS_OPTION_PREFIX = 'jetpack_sync_full_';
19
	const FULL_SYNC_TIMEOUT = 3600;
20
21
	public function name() {
22
		return 'full-sync';
23
	}
24
25
	function init_full_sync_listeners( $callable ) {
26
		// synthetic actions for full sync
27
		add_action( 'jetpack_full_sync_start', $callable );
28
		add_action( 'jetpack_full_sync_end', $callable );
29
		add_action( 'jetpack_full_sync_cancelled', $callable );
30
	}
31
32
	function init_before_send() {
33
		// this is triggered after actions have been processed on the server
34
		add_action( 'jetpack_sync_processed_actions', array( $this, 'update_sent_progress_action' ) );
35
	}
36
37
	function start( $modules = null ) {
38
		$was_already_running = $this->is_started() && ! $this->is_finished();
39
40
		// remove all evidence of previous full sync items and status
41
		$this->reset_data();
42
43
		if ( $was_already_running ) {
44
			do_action( 'jetpack_full_sync_cancelled' );
45
		}
46
47
		/**
48
		 * Fires when a full sync begins. This action is serialized
49
		 * and sent to the server so that it knows a full sync is coming.
50
		 *
51
		 * @since 4.2.0
52
		 */
53
		do_action( 'jetpack_full_sync_start' );
54
		$this->update_status_option( "started", time() );
55
56
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
57
			$module_name = $module->name();
58
			if ( is_array( $modules ) && ! in_array( $module_name, $modules ) ) {
59
				continue;
60
			}
61
62
			$items_enqueued = $module->enqueue_full_sync_actions();
63
			if ( ! is_null( $items_enqueued ) && $items_enqueued > 0 ) {
64
				// TODO: only update this once every N items, then at end - why cause all that DB churn?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
65
				$this->update_status_option( "{$module->name()}_queued", $items_enqueued );
66
			}
67
		}
68
69
		$this->update_status_option( "queue_finished", time() );
70
71
		$store = new Jetpack_Sync_WP_Replicastore();
72
73
		/**
74
		 * Fires when a full sync ends. This action is serialized
75
		 * and sent to the server with checksums so that we can confirm the
76
		 * sync was successful.
77
		 *
78
		 * @since 4.2.0
79
		 */
80
		do_action( 'jetpack_full_sync_end', $store->checksum_all() );
81
82
		return true;
83
	}
84
85
	function update_sent_progress_action( $actions ) {
86
87
		// quick way to map to first items with an array of arrays
88
		$actions_with_counts = array_count_values( array_map( 'reset', $actions ) );
89
90
		if ( ! $this->is_started() || $this->is_finished() ) {
91
			return;
92
		}
93
94
		if ( isset( $actions_with_counts['jetpack_full_sync_start'] ) ) {
95
			$this->update_status_option( "sent_started", time() );
96
		}
97
98
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
99
			$module_actions     = $module->get_full_sync_actions();
100
			$status_option_name = "{$module->name()}_sent";
101
			$items_sent         = $this->get_status_option( $status_option_name, 0 );
102
103
			foreach ( $module_actions as $module_action ) {
104
				if ( isset( $actions_with_counts[ $module_action ] ) ) {
105
					$items_sent += $actions_with_counts[ $module_action ];
106
				}
107
			}
108
109
			if ( $items_sent > 0 ) {
110
				$this->update_status_option( $status_option_name, $items_sent );
111
			}	
112
		}
113
114
		if ( isset( $actions_with_counts['jetpack_full_sync_end'] ) ) {
115
			$this->update_status_option( "finished", time() );
116
		}
117
	}
118
119
	public function is_started() {
120
		return !! $this->get_status_option( "started" );
121
	}
122
123
	public function is_finished() {
124
		return !! $this->get_status_option( "finished" );
125
	}
126
127
	public function get_status() {
128
		$status = array(
129
			'started'        => $this->get_status_option( 'started' ),
130
			'queue_finished' => $this->get_status_option( 'queue_finished' ),
131
			'sent_started'   => $this->get_status_option( 'sent_started' ),
132
			'finished'       => $this->get_status_option( 'finished' ),
133
			'sent'           => array(),
134
			'queue'          => array(),
135
		);
136
137
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
138
			$queued = $this->get_status_option( "{$module->name()}_queued" );
139
			$sent   = $this->get_status_option( "{$module->name()}_sent" );
140
141
			if ( $queued ) {
142
				$status[ 'queue' ][ $module->name() ] = $queued;
143
			}
144
			
145
			if ( $sent ) {
146
				$status[ 'sent' ][ $module->name() ] = $sent;
147
			}
148
		}
149
150
		return $status;
151
	}
152
153
	public function clear_status() {
154
		$prefix = self::STATUS_OPTION_PREFIX;
155
		delete_option( "{$prefix}_started" );
156
		delete_option( "{$prefix}_queue_finished" );
157
		delete_option( "{$prefix}_sent_started" );
158
		delete_option( "{$prefix}_finished" );
159
160
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
161
			delete_option( "{$prefix}_{$module->name()}_queued" );
162
			delete_option( "{$prefix}_{$module->name()}_sent" );
163
		}
164
	}
165
166
	public function reset_data() {
167
		$this->clear_status();
168
		require_once dirname( __FILE__ ) . '/class.jetpack-sync-listener.php';
169
		$listener = Jetpack_Sync_Listener::get_instance();
170
		$listener->get_full_sync_queue()->reset();
171
	}
172
173 View Code Duplication
	private function get_status_option( $option, $default = null ) {
174
		$prefix = self::STATUS_OPTION_PREFIX;
175
176
		$value = get_option( "{$prefix}_{$option}", $default );
177
		
178
		if ( ! $value ) {
179
			// don't cast to int if we didn't find a value - we want to preserve null or false as sentinals
180
			return $default;
181
		}
182
183
		return intval( $value );
184
	}
185
186
	private function update_status_option( $name, $value ) {
187
		$prefix = self::STATUS_OPTION_PREFIX;
188
		update_option( "{$prefix}_{$name}", $value, false );
189
	}
190
}
191