Book Image

MySQL 5.1 Plugin Development

Book Image

MySQL 5.1 Plugin Development

Overview of this book

MySQL has introduced a Plugin API with its latest version – a robust, powerful, and easy way of extending the server functionality with loadable modules on the fly. But until now anyone wishing to develop a plugin would almost certainly need to dig into the MySQL source code and search the Web for missing bits of the information.This is the first book on the MySQL Plugin API. Written together with one of the Plugin API primary architects, it contains all the details you need to build a plugin. It shows what a plugin should contain and how to compile, install, and package it. Every chapter illustrates the material with thoroughly explained source code examples.Starting from the basic features, common to all plugin types, and the structure of the plugin framework, this book will guide you through the different plugin types, from simple examples to advanced ones. Server monitoring, full-text search in JPEG comments, typo-tolerant searches, getting the list of all user variables, system usage statistics, or a complete storage engine with indexes – these and other plugins are developed in different chapters of this book, demonstrating the power and versatility of the MySQL Plugin API and explaining the intricate details of MySQL Plugin programming.
Table of Contents (16 chapters)
MySQL 5.1 Plugin Development
Credits
About the Authors
About the Reviewer
Preface

Server services


Over the years, MySQL developers have implemented a lot of functionality for the server to use. There are wrappers over the system functions such as my_open(), my_sync(), and my_malloc() that add additional features such as error checking and reporting. Compatibility wrappers such as my_snprintf() and pthread_mutex_lock() behave identically on all platforms and add additional features too. There are also various useful data structures such as red-black binary trees, dynamically growing hash tables, priority queues, and so on. Useful utility functions such as connection local memory allocator and character set support were developed specifically for the MySQL server run-time environment.

In many cases, plugins would like to use all of this and not reinvent the wheel. But how can they do that? Just calling any of these functions directly will create an additional dependency on the server—a dependency not covered by the Plugin API. Although not always possible, it is wise to avoid dependencies like that. MySQL developers can change internal details of the server implementation anytime—it is only the API that they promised to keep stable. If our plugin depends on such internal details, and they are changed, the best we can hope for is that the plugin will not load. However, it could cause a crash on load, or it may appear to work but produce incorrect results. There is no way to know in advance.

A safe, though time consuming, solution would be to ask MySQL developers to add functions we need to the plugin.h header. By doing this they add these functions to the Plugin API and promise to keep them stable. Or at least protected them with an API version number, as sometimes changes are unavoidable. If such an unavoidable change happens, the Plugin API version is incremented and old plugins stop loading. There will be no crash or incorrect results, MySQL will simply complain that the plugin requires an incompatible API version and will refuse to load a plugin.

This approach is safe, no crash, but not perfect. There is only one version number—the Plugin API version—but there can be hundreds of utility functions. An incompatible change of any single one of them requires the version to be incremented, and all plugins are invalidated—although most, if not all, plugins do not need or use this particular utility function and are not affected by the change. But MySQL does not know it, because there is one global version number that covers everything.

What is really needed is a fine-grained version control, to track interface changes on a function level, one version per function, or at least per a group of related functions. A plugin stores version numbers for all of the functions it uses and MySQL checks them when it loads a plugin. Ideally, it should be completely automatic—we do not want to maintain a list of all functions (and their versions) that our plugin needs.

This is exactly what Server Services are. Fine-grained version control—one version per service, that is a group of functions (a group can be as small as one function though). Automatic dependency tracking—we do not need to think about it, it just works; the versions for all services that we have used in our plugin are automatically recorded in the plugin binary (.dll or .so file). They are automatically checked when a plugin is loaded to guarantee complete API compatibility. Changes in functions that our plugin does not use will not affect the compatibility of our plugin, even if they may affect other plugins. It is completely transparent and does not require any changes in the plugin source code—calling a function from a service is as simple as calling a normal function. We can simply write:

my_snprintf(buf, sizeof(buf), "string=%s", str);

This will call an appropriate function from an appropriate service.

What are the drawbacks? It is almost automatic and transparent, but not quite. There is one manual step—we need to link our plugin with libmysqlservices.a. Usually, it means adding -lmysqlservices to LDFLAGS in the Makefile.am file. In Windows, there is no need to do even that.

Another issue is that services do not cover all MySQL internal functionality yet. Their number is growing, we can expect more services to appear. Eventually, everything that MySQL developers want to make accessible for plugins will be available via services. But at the time of writing, there are only two services in the MySQL 5.5 source tree: my_snprintf and thd_alloc.

my_snprintf

This service provides two functions: my_snprintf() and my_vsnprintf(). They are roughly equivalent to the system snprintf() and vsnprintf() (leaving aside the fact that not all systems provide them) with the following differences:

  • They do not support all printf() format features. For example, left-padding is not implemented.

  • They produce identical results on all operating systems, compilers, and architectures—passing a null pointer for %s prints (null) (while system printf() either does that or crashes). Floating point numbers are printed identically everywhere as they use MySQL internal routines for conversion. Printing a pointer with %p always adds the 0x prefix (a system printf() either does it or not).

  • They support a few non-standard extensions, such as printing a string with embedded null bytes (using %b format) or quoting identifiers with backticks according to MySQL quoting rules (using %`s format).

The complete documentation for this service is in the mysql/service_my_snprintf.h file.

thd_alloc

This service gives us a specialized memory allocation function thd_alloc() as well as helper functions thd_calloc(), thd_strdup(), thd_strmake(), and thd_memdup().

There are two main differences between malloc() and thd_alloc():

  • The system malloc() typically allocates memory from a global memory pool. It means that when many threads want to allocate memory in parallel, malloc() needs to protect its shared data structures, which causes mutex locks and reduces concurrency. The thd_alloc() function takes memory from a thread local memory pool, and as different threads use different pools the concurrency overhead disappears. In other words, thd_alloc() is much faster than malloc() when MySQL is serving many connections at the same time.

  • There is no need to free the memory. All memory allocated with thd_alloc() is automatically freed when the processing of the current SQL statement ends. It significantly simplifies plugin memory management as we do not need to worry about memory leaks anymore.

It all means that this service is perfect for small and medium-sized allocations that we need only for a short time, otherwise we are better off with a good old malloc().

The complete documentation for this service is in the mysql/service_thd_alloc.h file.