Download in PDF
  1. Abstract
  2. Introduction
  3. Background
  4. Deploying and Running MoodleAzure
  5. Packaging, Configuring and Deploying the Solution
  6. Implementation Details: What Changed
  7. Horizontally Scaling the Application
  8. Conclusion

Implementation Details: What Changed

In this section we go over the implementation details of what was added and what was changed in both, Moodle and the PHP Azure SDK. – The first thing that is noticeable is the addition of the file. In this file we detect whether the application is running in the cloud. The “RoleRoot” environment variable is set when this is the case. Configuration values for table and blob storage services are also provided. We also register the ‘azure://’ custom stream wrapper Finally, the table storage-based session handler from the PHP Azure SDK is registered. – This file was originally based on the file. It was however heavily modified to use the sqlsrv extension instead. One of the more notable differences is the use of Sql Azure system tables for metadata extraction. Some of the queries to extract column names, indexes, object types, and the like, were querying metadata tables that simply do not exist in in Sql Azure. They do however have an equivalent. The other obvious change is the way queries are executed. Notice the use of a Forward-only cursor when performing query execution (line 649). The reason behind this is that under Keyset mode, the database needs to create a temporary table which works in Azure, but it does not yield an acceptable performance.

formslib.php – Only a couple of lines changed here (111 and 837). These changes ensure that the form actions do not point to the Azure load balancer port 20000. When deploying Azure applications, PHP will rewrite the host (HTTP_HOST environment variable) to be the same as the one being accessed, but on a different port – the load balancer’s --. This is a known issue documented in:

gdlib.php – Turns out that imagejpeg, imagepng, and imagegif of the GD2 library does not support saving images using a registered stream. The workaround was to create the Azure versions of these functions (starting on line 325): ImageJpegAzure, ImagePngAzure, and ImageGifAzure. These functions create a temporary file to write the image file using GD2’s native functions, and then write the file contents to the specified blob. All the calls to imagejpeg, imagegif, and imagepng were replaced with their Azure equivalents (lines 244 and 313).

graphlib.php – The only change in this file was the importing of gdlib.php at the beginning of the file and the replacement of all the calls to imagejpeg, imagegif, and imagepng with their azure equivalents.

field.class.php – Lines 448 and 255 replace imagejpeg and imagepng with their Azure equivalents as well. The importing of the gdlib.php script is done in the top of the script.

Storage.php – The PHP Azure SDK implements 2 policies: RetryN and NoRetry. The default policy to use when connecting to storage services is the NoRetry policy. After some testing, we decided to change the default policy to RetryN because we discovered that sometimes calls to storage services do fail. See line 201.

Stream.php – This is the file that contains the most modifications and additions. For instance, this implementation keeps a cache of blob instances and container names. This makes the stream wrapper more efficient because it does not have to fetch blob metadata or check whether a container exists every time an operation is required. The caches are only kept per call, and if within the same call a new blob is created, the caches get invalidated through the invalidateCache function. The caches are only valid for the current request.  Whenever there is a file added, or the simulated file system changes, the cache is also invalidated. The getFileName function also changed. Mostly because we need a way to simulate multi-level folder structures in blobs. This is done by replacing the forward slash ‘/’ with 3 underscores ‘___’ . In this way, whenever the PHP application needs to list “files” within a “folder” we will just take the blobs that start with the given folder prefix. For example, if file ‘azure://users/1/picture/1.jpg’ is requested, we will need to read the blob named ‘moodledata/users___1___picture___1.jpg’.

Opening a stream for appending (see line 256) would throw an exception whenever the blob did not exist before. But the append mode of a PHP stream is supposed to attempt to create a file. Therefore, we will only try to read the blob. If it doesn’t exist, we will already have the temp file we are writing to and when closing the stream the temp file will be automatically written to the blob with the same name. Another challenge was to correctly handle the usrl_stat method call. Whenever the operating system needs to know the metadata of a files system entry (files or folders), it needs to fill out such information in the url_stat method of the stream wrapper. But in the original implementation, there was too little metadata available to simulate folders. At the OS level, the differentiation between files and folders is stored in the ‘mode’ entry. Folder modes are represented by 040777 and file modes are represented by 010066 (see line 566). Thus, blobs stored with a ‘simulated-folder’ content encoding will return a 040777 mode. Which takes us to the next method call: mkdir. Mikdir is the method call to create folders. As stated before, we are simulating folders with blobs. We store the folder-simulating blobs with a content encoding of ‘simulated-folder’. See line 620 for further details. The rmdir method (see line 672) also needed modification because when deleting a folder, we need to delete all of its contents. In Azure, that means we need to delete all the blobs starting with the folder prefix. Finally, the dir_opendir implementation was changed so it would allow for listing only blobs with the specified path prefix.

Last edited Oct 28, 2010 at 4:41 PM by unosquare, version 1


No comments yet.