Store datasets directly in shared memory with PHP

A step-by-step guide on how to use shared memory in PHP as a storage option

Learn about shared memory and how to use it in web applications as a data storage option, benefiting from high speed, reliability, and data exchange with other applications. The examples provided will show its use to solve common problems in web application development.

Klaus Silveira (contact@klaussilveira.com), Software Engineer and Instructor, 4Linux

Klaus SilveiraKlaus Silveira, a software engineer and instructor focused on PHP, is passionate about developing intelligent solutions for the web and contributing for the open source world with projects like SimpleString and SimpleSHM. He works at 4Linux, a Brazilian company dedicated to free software solutions. He is responsible for developing enterprise web applications and PHP courses that prepare developers for the Zend PHP Certification exam.



17 January 2012

Also available in Chinese Russian Japanese

Overview

Shared memory is an efficient way to exchange data between applications in the same machine. One process can create a memory segment that other processes can access, as long as it assigns the correct permissions. Every segment has a unique ID, called shmid that points to an area of physical memory where other processes can manipulate it. Once created, and given proper permissions, other processes in the same machine can manipulate those segments by: read, write, and delete.

This means that an application written in C can share information with an application written in other languages, such as Java™ or PHP. They can all share information, as long as they can access and understand that information. Shared memory is widely used with implementations made available for most languages, so access should not be a problem. As for understanding information, we can use a standard format like XML or JSON.

Use of shared memory is a fast method of data exchange between processes, mainly because there is no kernel involvement in passing data after the segments are created. Methods of this kind are often called interprocess communication (IPC). Other IPC methods include pipes, message queues, RPC, and sockets. This fast and reliable ability to exchange data between applications is invaluable when working with an ecosystem of applications needing to communicate with each other. The usual method of using databases to exchange information between applications often causes slow queries and even blocking I/O, depending on the size of the ecosystem. With shared memory, there's no I/O slowing a developer down.

This article's proposal is simple, learn how to create and manipulate shared memory segments with PHP and use them to store datasets that other applications can use. Even without a plan to use shared memory for data exchange, it is beneficial because it allows applications to stay away from I/O issues. Storing datasets directly in memory has many advantages, from web services data cache to session sharing. It's a very useful concept that every PHP developer should know.

Shared memory and PHP

PHP has a wide variety of extensions available, as does shared memory. With a few shared functions, and without having to install any extension, developers are able to easily manipulate segments.


Create segments

Shared memory functions are similar to the file manipulation functions, but instead of working with a stream, you'll be working with a shared memory access ID. The first example of this is the shmop_open function, which allows you to open an existing segment or create a new one. This function is very similar to the classic fopen function that opens streams for file manipulation, returning a resource that can later be used by other functions that wish to read or write in to that opened stream. Let's look at shmop_open in Listing 1.

Listing 1. The shmop_open function
<?php

$systemid = 864; // System ID for the shared memory segment
$mode = "c"; // Access mode
$permissions = 0755; // Permissions for the shared memory segment
$size = 1024; // Size, in bytes, of the segment

$shmid = shmop_open($systemid, $mode, $permissions, $size);

?>

The first thing presented is the system ID parameter. This is the number that identifies the shared memory segment in the system. The second parameter is the access mode, which is very similar to the access mode of the fopen function. You can access a segment in four different modes:

  • Mode "a", which allows you to access the segment for read-only
  • Mode "w", which allows you to access the segment for read and write
  • Mode "c", which creates a new segment, or if the segment already exists, try to open for read and write
  • Mode "n", which creates a new segment, and if the segment already exists, fail

The third parameter is the permissions of the segment. You must provide an octal value here.

The fourth parameter provides the segment size in bytes. Before writing in to a segment, you must allocate a proper number of bytes on it.

Note that this function returns an ID number that can be used with other functions for manipulating the shared memory segment. This ID is the shared memory access ID and is different from the system ID, passed as a parameter. Be careful not to confuse the two. On failure, shmop_open will return FALSE.


Write in to segments

Use the shmop_write function to write in to a shared memory block. This function is simple to use and accepts only three parameters. This function, as shown in Listing 2, is simple to use and accepts only three parameters.

Listing 2. Use shmop_write to write in to a shared memory block
<?php

$shmid = shmop_open(864, 'c', 0755, 1024);
shmop_write($shmid, "Hello World!", 0);

?>

There is a resemblance with the fwrite function, which has two parameters: the opened stream resource, returned by fopen, and the data you wish to write. The shmop_write function does just that.

The first parameter is the ID returned by shmop_open and identifies the shared memory block you're manipulating. The second parameter is the data you want to store and, finally, the third parameter is where you want to start writing. By default, we always use 0 here to start writing from the beginning. Note that this function returns FALSE on failure and the number of bytes written on success.


Read from segments

Reading from shared memory segments is simple. All you need is an opened segment and the shmop_read function. This function accepts a few parameters and works similarly to fread. See Listing 3 to read the contents of a file with PHP.

Listing 3. Use shmop_read to read the contents of a file
<?php

$stream = fopen('file.txt', 'r+');
fwrite($stream, "Hello World!");
echo fread($stream, 11);

?>

Reading the contents of a shared memory segment is similar, as shown in Listing 4:

Listing 4. Read the contents of a shared memory segment
<?php

$shmid = shmop_open(864, 'c', 0755, 1024);
shmop_write($shmid, "Hello World!", 0);
echo shmop_read($shmid, 0, 11);

?>

Observe the parameters here. The shmop_read function will accept the ID returned by shmop_open, which is already known to us, but it also accepts two other parameters. The second parameter is where you want to start reading from the segment; while the third one is the amount of bytes you want to read. The second parameter might always be 0, the beginning of the data, but the third parameter can be a problem because we may not know how many bytes we want to read.

This is very similar to the behavior we had in the fread function, which accepts two parameters: the opened stream resource, returned by fopen, and how many bytes you want to read from that stream. Use the filesize function, which returns the amount of bytes in a file to read it in its entirety.

Fortunately, the shmop_size function returns the size in bytes of a segment, similar to the filesize function, when working with shared memory segments. See Listing 5.

Listing 5. The shmop_size function returns the size in bytes of a segment
<?php

$shmid = shmop_open(864, 'c', 0755, 1024);
shmop_write($shmid, "Hello World!", 0);

$size = shmop_size($shmid);
echo shmop_read($shmid, 0, $size);

?>

Remove a segment

We learned how to open, write, and read shared memory segments. To complete our CRUD class, we need to learn how to remove segments. Such a task can be easily done by using the shmop_delete function, which expects only one parameter: the shared memory ID that we want to remove.

Listing 6. The shmop_delete marks segment for deletion
<?php

$shmid = shmop_open(864, 'c', 0755, 1024);
shmop_write($shmid, "Hello World!", 0);
shmop_delete($shmid);

?>

This doesn't actually remove the segment. It marks the segment for deletion since shared memory segments cannot be removed while there are other processes using it. The shmop_delete function will mark the segment for deletion and prevent any other process from opening it. To remove it we need to close the segment.


Close a segment

Opening a shared memory segment "attaches" to it. After attaching to the segment, we can read and write from it, but once we've finished our manipulation, we must detach from it. This is done using the shmop_close function in Listing 7.

This is very similar to the fclose function when working with files. After opening a stream with a file and reading or writing from it, we must close it or locks will occur.

Listing 7. Use shmop_close to detach from a segment
<?php

$shmid = shmop_open(864, 'c', 0755, 1024);
shmop_write($shmid, "Hello World!", 0);
shmop_delete($shmid);
shmop_close($shmid);

?>

Use shared memory as a storage option

With a basic knowledge of shared memory and basic CRUD operations on shared memory segments, it's now time to put this knowledge to work. We can use shared memory as a unique storage alternative, providing benefits such as fast read/write operations and process interoperability. For a web application, this means:

  • Cache storage (database queries, web services data, external data)
  • Session storage
  • Data exchange between applications

Before we proceed, I would like to present a small library called SimpleSHM. SimpleSHM is a small abstraction layer for shared memory manipulation using PHP, allowing easy manipulation of segments in an object-oriented way. This library helps create much cleaner code when writing a small application that uses shared memory for storage. To get started into SimpleSHM, grab a tarball from the GitHub page.

You have three methods to work with: read, write, and delete. Simply instantiating an object from the class will control the shared memory segment opening. Listing 8 shows basic use.

Listing 8. SimpleSHM basic use
<?php

$memory = new SimpleSHM;
$memory->write('Sample');
echo $memory->read();

?>

Note that an ID is not passed for the class. If an ID isn't passed, it will choose a number randomly and open a new segment with that number. We can pass a number as a parameter for the constructor to open an existing segment or to create with a specific ID as shown in Listing 9.

Listing 9. Open a specific segment
<?php

$new = new SimpleSHM(897);
$new->write('Sample');
echo $new->read();

?>

The magic method __destructor takes care of calling shmop_close on the segment to unset the object in order to detach from the segment. We'll call this "SimpleSHM 101." Now let's use this for a higher purpose: using shared memory as storage. Storing datasets requires serialization since arrays or objects cannot be stored in memory. While JSON is used here for serialization, any other method, such as XML or the built-in PHP serialization features, will suffice. See Listing 10 for an example.

Listing 10. Use shared memory as storage
<?php

require('SimpleSHM.class.php');

$results = array(
	'user' => 'John',
	'password' => '123456',
	'posts' => array('My name is John', 'My name is not John')
);

$data = json_encode($results);

$memory = new SimpleSHM;
$memory->write($data);
$storedarray = json_decode($memory->read());

print_r($storedarray);

?>

We successfully serialized an array into a JSON string, stored in a shared memory block, read from it, unserialized the JSON string, and displayed the stored array. This seems basic, but imagine the possibilities of this snippet. You can use it for storing the results of a web service request, database query, or even template engine cache. Reading and writing from memory will provide much higher performance than reading and writing from disk.

Using this storage technique is not only useful for cache, but also for data exchange between applications, as long as data is stored in a format readable by both ends. Don't underestimate the power of shared memory in web applications. There are many different ways to cleverly implement this kind of storage and the only limit is a developer's creativity and skill.


Conclusion

This article covers most of the tools available in PHP's toolkit for manipulating shared memory segments, and explains how shared memory works. Further, it offers suggestions for improving web applications and outlines some of the factors to consider when creating a solution for common web application problems. The concepts and implementation guidelines can help you establish a starting point. The early model we built can help you envision more complex features and solutions.

What’s next?

We outlined some common problems that are a perfect fit for shared memory, such as caching, session sharing, and common data exchange between applications. This introduction to shared memory provides you the opportunity to explore much more elegant solutions to common problems. Feel free to extend the current implementation of SimpleSHM to match your needs and contribute the changes back to the project.

Resources

Learn

  • Michael Kerrisk's book The Linux Programming Interface has excellent chapters about interprocess communication and chapters 45 to 48 are dedicated to System V IPC.
  • Dave Marshall’s "IPC:Shared Memory" article has an interesting and pragmatic approach to shared memory functions in C language.
  • Richard Stevens UNIX Network Programming has great technical content and several implementations in C. Check the sample chapter.
  • Expand your PHP skills by checking out IBM developerWorks' PHP project resources.
  • Read other developerWorks articles and tutorials related to PHP content.
  • Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
  • Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
  • Follow developerWorks on Twitter.

Get products and technologies

  • Innovate your next open source development project with IBM trial software, available for download or on DVD.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=787970
ArticleTitle=Store datasets directly in shared memory with PHP
publish-date=01172012