Home  >  Article  >  Backend Development  >  Introduction to atomic operations and file lock flock in PHP (code example)

Introduction to atomic operations and file lock flock in PHP (code example)

不言
不言forward
2019-01-28 10:00:482812browse

This article brings you an introduction to atomic operations and file lock flock in PHP (code examples). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

php atomic operation, file lock flock, database transaction

php does not inherit the unix lock supported by the POSIX standard, and only encapsulates a Linux system call flock (semaphore can also be used as a lock). It stands to reason that the locking mechanism can also be used, although it is less efficient.
The php script runs in a fastcgi container, and fastcgi is multi-process, so if the php program accesses critical resources, it will inevitably cause incorrect program results.
It is estimated that we should also consider the problem of fastcgi container

Problem description: The tool used by hackers to brush our backend
There will be a refund when canceling the order. The hacker canceled the order concurrently, resulting in multiple refunds
If the requests come one by one, even if the interval is 100 milliseconds, there will be no problem

A PHP processing process is: Read the refund flag, find that there is no refund, refund, and then set the refund flag
The problem is that multiple requests arrive at the same time, and the refund signs read out are all unrefunded, so multiple requests have been refunded
The same php file is requested multiple times at the same time, at the same time

Using PHP file lock flock We tried but it didn’t work, so we still used C queue
Used C to listen to a port, directly receive HTTP packets, and then return the packets in HTTP format, PHP program I use curl to access my C program.
It is equivalent to remote calling and can be deployed to other servers for distribution

Many times, we do not consider our The parallel ability of PHP code, especially when our PHP code can read and write to a certain resource. But this does not mean that all operations in PHP are atomic, transactional, and parallelizable. Since the PHP script runs in the fastcgi container, and fastcgi is multi-process, if the PHP program accesses critical resources, it will inevitably cause incorrect program results.

The solution to the problem is to use the lock mechanism. PHP does not inherit the Unix locks supported by the POSIX standard: such as record locks fcntl, thread locks, etc., but only encapsulates a Linux system call flock (semaphore can also be used as a lock), flock in the form of flock($fp,$type), Where $fp is the file handle, and $type is:
/* When a file is opened for reading and writing, it is usually necessary to add a lock mechanism to the file*/

1. LOCK_SH shared lock :
Usually a shared lock is required when a process requests a read operation from a file. Shared locks can support read operations between any processes. If you write a file with a shared lock, the process will block and enter the SLEEP state until the shared lock is unlocked.

2. LOCK_EX exclusive lock:
usually a process Add an exclusive lock to the file's write operation. Once the file is locked, any other process will be blocked when accessing the file until it is unlocked.

3. LOCK_UN Unlocking:
Unlock the locked file handle

This locking method can certainly ensure the atomicity of the locked program block, but at the same time it also sacrifices the atomicity of the program. Efficiency, therefore, in our actual program, as little program logic as possible (especially exclusive locks) should be embedded between the locking and unlocking codes of the program to ensure that the program is unlocked as soon as possible.

Finally, attach the program after adding the locking mechanism:

<?php 
$usrinfo = isset($_GET["usrinfo"])?$_GET["usrinfo"]:exit(1); 
$stinfo = isset($_GET["stinfo"])?$_GET["stinfo"]:exit(1); 
echo $stinfo; 
$pid = posix_getpid(); 
$fp = fopen(“usrinfo.txt”,”a+”); 
$num = rand(0,100000); 
flock($fp,LOCK_EX); 
fwrite($fp,”user:”.$usrinfo.” stinfo:”.$stinfo.”–”.$pid.”–”.$num.”\n”); 
fwrite($fp,”talking 1 — pid:$pid and num:$num\n”); 
flock($fp,LOCK_UN); 
fclose($fp);

Normally, running this program will produce correct results.

What method can be used to ensure atomicity during batch operations?
For example: delete multiple articles, but one of them has been deleted. Assuming an error occurs here, how to roll back the entire operation and locate the error message?
Database transactions guarantee atomicity but cannot locate error information. But what should we do if we encounter a scenario where transactions cannot be used?

It is most reasonable to use database transactions. Error information can be recorded. If an operation fails, an error will be thrown.
Apply logic to ensure that every operation is recorded, and success or failure is recorded. If something goes wrong in the middle, you can roll back the success. Generally, our deletion is a fake deletion, so it is very easy. If it is deleted, complete information must be recorded when recording.

PHP uses file locks to simulate process locks to achieve atomic operations
Use PHP to implement atomic operations, but PHP itself does not provide a process lock mechanism. Use PHP file lock mechanisms to simulate process locks through file locks to achieve atomic operations. operate.

Before the code for the atomic operation, use an exclusive lock to open a file. The code is as follows:

$fp = fopen( LOCK_FILE_PATH, "r" );
if (!$fp) {
 echo "Failed to open the lock file!"; 
 exit(1);//异常处理
 }
flock ( $fp, LOCK_EX );

After the code for the atomic operation, unlock the file and close the file. The code is as follows:

flock ( $fp, LOCK_UN );
fclose ( $fp );

The overall pseudo code is:

define("LOCK_FILE_PATH", "/tmp/lock");
if( !file_exists(LOCK_FILE_PATH) ){ 
$fp = fopen( LOCK_FILE_PATH, "w" );
fclose ( $fp );
}
$fp = fopen( LOCK_FILE_PATH, "r" );
if (!$fp) {
echo "Failed to open the lock file!";
exit(1);//异常处理
}
flock ( $fp, LOCK_EX );
//此处添加原子操作代码
flock ( $fp, LOCK_UN );
fclose ( $fp );

The above can implement PHP atomic operations and avoid conflicts.

php atomic operations and mysql atomic operations

The commonly used method for atomic operations is to implement data rollback. It is quite simple to use PHP to implement database rollback operations:
1, establish a database connection
2, mysql_query('BEGIN'); open a transaction
3, $SQL = "...";
mysql_query($SQL); Perform corresponding database operations
4, Determine rollback conditions:
if(mysql_errno)
{
print mysql_error();
mysql_query('ROLLBACK'); Roll back if an error occurs
exit();
}
5, you can repeat the above steps 3 and 4 to start the process (Other operations can be added in the middle, not limited to database updates, but be careful not to let a transaction take too long, because it locks all the tables you use, which will affect the use of other programs)
You can also add several After a correct SQL update statement, deliberately write an incorrect one to see if it is rolled back.
6, end the rollback operation
mysql_query('COMMIT'); Being able to get here means that the above database operations are all correct and are officially submitted for execution

This is the entire process of using PHP to implement atomic operations , Special attention needs to be paid to establishing a table structure that supports data rollback operations.
In addition, there are other ways to end the rollback operation besides commit.


The above is the detailed content of Introduction to atomic operations and file lock flock in PHP (code example). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:cnblogs.com. If there is any infringement, please contact admin@php.cn delete