The program should not be locked when writing the log file

The program should not be locked when writing the log file

Log (log)

In order to make their ideas more clearly, here I would call log to log. Because the log This word has two meanings, as detailed Baidu Encyclopedia interpretation or Wikipedia Interpretation .

  • Diary another argument. "Chi" word itself as a "record" means, log on daily records (usually associated with the author).
  • Server log ( operation server log), recording servers and other computer equipment or software.

We are speaking here, of course, the server log, which is the   Server log  .

Write log

General will write log, follow these steps:

int fd = open(path)
write(fd, sign_append) fclose(fd)

 

Explain the above code:

1. int fd = open(path) 

System call will be opened by a file descriptor, or in other languages ​​may also be referred to as a resource descriptor, the resource type, or handle.

 

2. write(fd, append = 1)

write system calls, plus append flag, performs seek and write two system calls, but this system call is atomic.

Atomic means that seek and write will be executed simultaneously, there will be two threads produces a cross, a thread must complete the implementation of seek and write, b thread to continue execution (thread here say, because the thread is the basic unit of cpu scheduling) .

So nginx, we add append flag, do not lock the thread.

 

3. fclose(fd)

Close descriptor.

linux in general there is a limit on the maximum number of open file descriptors, if you do not close the descriptor, is likely to cause big bug.

See the linux restricted as follows (wherein represents the number of open files can open the file):

$ ulimit -a

core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 15732
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 15732
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

 

So, if the system is called, then append never be locked.

 

Why php language with the append write the log should be locked?

If according to the above statement, we can set a good write the append flag and then you can go to sleep, the file will never conflict.

But (generally one but) you see php framework will be locked before file_put_contents of append.

Thus, I suspected because the underlying implementation file_put_contents not achieve atomicity.

Follow-up source (for a non-programmer or php php underlying source can skip the uninteresting):

file_put_contents underlying implementation: 

// file.c
/* {{{ proto int|false file_put_contents(string file, mixed data [, int flags [, resource context]])
   Write/Create a file with contents data and return the number of bytes written */
PHP_FUNCTION(file_put_contents)
{
...
case IS_STRING:
   if (Z_STRLEN_P(data)) {
      numbytes = php_stream_write(stream, Z_STRVAL_P(data), Z_STRLEN_P(data));
      if (numbytes != Z_STRLEN_P(data)) {
         php_error_docref(NULL, E_WARNING, "Only %zd of %zd bytes written, possibly out of free disk space", numbytes, Z_STRLEN_P(data));
         numbytes = -1;
      }
   }
   break;
...
}

// php_streams.h
PHPAPI ssize_t _php_stream_write(php_stream *stream, const char *buf, size_t count);
#define php_stream_write_string(stream, str)   _php_stream_write(stream, str, strlen(str))
#define php_stream_write(stream, buf, count)   _php_stream_write(stream, (buf), (count))

// streams.c
PHPAPI ssize_t _php_stream_write(php_stream *stream, const char *buf, size_t count)
{
  ...
   if (stream->writefilters.head) {
      bytes = _php_stream_write_filtered(stream, buf, count, PSFS_FLAG_NORMAL);
   } else {
      bytes = _php_stream_write_buffer(stream, buf, count);
   }

   if (bytes) {
      stream->flags |= PHP_STREAM_FLAG_WAS_WRITTEN;
   }

   return bytes;
}

/* Writes a buffer directly to a stream, using multiple of the chunk size */
static ssize_t _php_stream_write_buffer(php_stream *stream, const char *buf, size_t count){
...
while (count > 0) {
   ssize_t justwrote = stream->ops->write(stream, buf, count);
   if (justwrote <= 0) {
      /* If we already successfully wrote some bytes and a write error occurred
       * later, report the successfully written bytes. */
      if (didwrite == 0) {
         return justwrote;
      }
      return didwrite;
   }

   buf += justwrote;
   count -= justwrote;
   didwrite += justwrote;

   /* Only screw with the buffer if we can seek, otherwise we lose data
    * buffered from fifos and sockets */
   if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
      stream->position += justwrote;
   }
}

}

// php_streams.h
/* operations on streams that are file-handles */
typedef struct _php_stream_ops  {
   /* stdio like functions - these are mandatory! */
   ssize_t (*write)(php_stream *stream, const char *buf, size_t count);
   ssize_t (*read)(php_stream *stream, char *buf, size_t count);
   int    (*close)(php_stream *stream, int close_handle);
   int    (*flush)(php_stream *stream);

   const char *label; /* label for this ops structure */

   /* these are optional */
   int (*seek)(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset);
   int (*cast)(php_stream *stream, int castas, void **ret);
   int (*stat)(php_stream *stream, php_stream_statbuf *ssb);
   int (*set_option)(php_stream *stream, int option, int value, void *ptrparam);
} php_stream_ops;
 
// plain_wrapper.c
static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t count)
{
   php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;

   assert(data != NULL);

   if (data->fd >= 0) {
#ifdef PHP_WIN32
      ssize_t bytes_written;
      if (ZEND_SIZE_T_UINT_OVFL(count)) {
         count = UINT_MAX;
      }
      bytes_written = _write(data->fd, buf, (unsigned int)count);
#else
      ssize_t bytes_written = write(data->fd, buf, count);
#endif
      if (bytes_written < 0) {
         if (errno == EWOULDBLOCK || errno == EAGAIN) {
            return 0;
         }
         if (errno == EINTR) {
            /* TODO: Should this be treated as a proper error or not? */
            return bytes_written;
         }
         php_error_docref(NULL, E_NOTICE, "write of %zu bytes failed with errno=%d %s", count, errno, strerror(errno));
      }
      return bytes_written;
   } else {

#if HAVE_FLUSHIO
      if (data->is_seekable && data->last_op == 'r') {
         zend_fseek(data->file, 0, SEEK_CUR);
      }
      data->last_op = 'w';
#endif

      return (ssize_t) fwrite(buf, 1, count, data->file);
   }
}

 

This function is a function php_stdiop_write final call 

_Php_stream_write_buffer function in the string is divided into a plurality chunksize, each chunksize to 8096 bytes, respectively write.

If you do not lock, then after more than 8096 bytes, multiple processes to write the log will be confusion.

Moreover, php document also shows:

 

 

 

 So, depending on the final language, specific analysis needs.

Guess you like

Origin www.cnblogs.com/wudanyang/p/12113348.html