Fix race condition in update_product_stock
Modify the increment and decrement SQL query in WC_Product_Data_Store_CPT::update_product_stock to be atomic. This fixes a race condition in concurrent order placement.
This commit is contained in:
parent
23e555823b
commit
ca996a8941
|
@ -1356,9 +1356,14 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||||
|
|
||||||
if ( 'set' === $operation ) {
|
if ( 'set' === $operation ) {
|
||||||
$new_stock = wc_stock_amount( $stock_quantity );
|
$new_stock = wc_stock_amount( $stock_quantity );
|
||||||
|
|
||||||
|
// Generate SQL.
|
||||||
|
$sql = $wpdb->prepare(
|
||||||
|
"UPDATE {$wpdb->postmeta} SET meta_value = %f WHERE post_id = %d AND meta_key='_stock'",
|
||||||
|
$new_stock,
|
||||||
|
$product_id_with_stock
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// @todo: potential race condition.
|
|
||||||
// Read current stock level and lock the row. If the lock can't be acquired, don't wait.
|
|
||||||
$current_stock = wc_stock_amount(
|
$current_stock = wc_stock_amount(
|
||||||
$wpdb->get_var(
|
$wpdb->get_var(
|
||||||
$wpdb->prepare(
|
$wpdb->prepare(
|
||||||
|
@ -1368,25 +1373,27 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Calculate new value.
|
// Calculate new value for filter below. Set multiplier to subtract or add the meta_value.
|
||||||
switch ( $operation ) {
|
switch ( $operation ) {
|
||||||
case 'increase':
|
case 'increase':
|
||||||
$new_stock = $current_stock + wc_stock_amount( $stock_quantity );
|
$new_stock = $current_stock + wc_stock_amount( $stock_quantity );
|
||||||
|
$multiplier = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$new_stock = $current_stock - wc_stock_amount( $stock_quantity );
|
$new_stock = $current_stock - wc_stock_amount( $stock_quantity );
|
||||||
|
$multiplier = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate SQL.
|
||||||
|
$sql = $wpdb->prepare(
|
||||||
|
"UPDATE {$wpdb->postmeta} SET meta_value = meta_value %+f WHERE post_id = %d AND meta_key='_stock'",
|
||||||
|
wc_stock_amount( $stock_quantity ) * $multiplier, // This will either subtract or add depending on operation.
|
||||||
|
$product_id_with_stock
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate SQL.
|
$sql = apply_filters( 'woocommerce_update_product_stock_query', $sql, $product_id_with_stock, $new_stock, $operation );
|
||||||
$sql = $wpdb->prepare(
|
|
||||||
"UPDATE {$wpdb->postmeta} SET meta_value = %f WHERE post_id = %d AND meta_key='_stock'",
|
|
||||||
$new_stock,
|
|
||||||
$product_id_with_stock
|
|
||||||
);
|
|
||||||
|
|
||||||
$sql = apply_filters( 'woocommerce_update_product_stock_query', $sql, $product_id_with_stock, $new_stock, 'set' );
|
|
||||||
|
|
||||||
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared
|
$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue