Piotras' blog
Midgard2 - new epoch
Posted on 2009-04-29 13:10:02 EEST.
Today, we made first stable release for the new Midgard2 generation. For years, Midgard focused on PHP and well known LAMP platform. With Midgard2 we created completely new architecture based on stable and widely used libraries:
- GLib
- GObject
- LibGDA
- LibXML
And from pure web environment our target became: desktop, mobile devices and web as well. With Midgard2 you can select the language you would like to write your favorite application:
- C
- Python
- PHP
- Objective-C
Binary packages will be available soon at OBS repository. And later on, you can expect them also in maemo extras.
When MySQL goes away
Posted on 2009-03-18 11:47:17 EET.
I am debugging Midgard problem related to MySQL 2006 error. It's well known as "MySQL server has gone away". What I found so far, is an easy way to set very short timeout for debugging purposes. I execute such query in MySQL shell (and it sets timeout for 15 seconds):
set global wait_timeout = 15;
Similarly, you set increase yout timeout if sercer times out too quickly:
set global wait_timeout = 86400;
This one sets timeout for 24 hours.
Once you do so, you can notice different values when executing show variables query. Do not worry, the query you used, returns variables from the session you are just running.
Consequence and consistence
Posted on 2009-02-12 20:01:49 EET.
I tell it here and there. But people tend to forget, so it's better to write it down. I know, some people (developers) already don't like me, but it's not really my fault they write bad code. And since now, I will (consequently) write about something they produce. Ah! It's PHP or Zend Engine 2, if I forgot to mention.
Let's look at one file, php_reflection.c from reflection extension.
/* Invoke the __toString() method */
ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring") - 1, 1);
So what is the method name? __tostring or __toString? What minimal alphabet they use?
And note second line:
ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring") - 1, 1);
And one more from the same file:
zend_hash_find(EG(function_table), lcname, name_len + 1, (void **)&fptr);
and one more:
zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
What's the deal with those three lines of code? API is created such way, so it forces you to pass length of the passed string. So if you look at examples above, how do you count length of the string?
midgard_datetime
Posted on 2009-01-22 18:39:20 EET.
I started to work on midgard_datetime class. Pure PHP class which should represent any property of Midgard MgdSchema object which holds datetime string. A pure, means that it focuses on PHP language only, and in fact, it's implemented in midgard extension.
Why midgard_datetime? And not just simple DateTime class, as suggested in related ticket? Answer is simple. PHP has limits. Imagine, every datetime property is propagated as DateTime object. And when you want to read it, you simply invoke format() method. But what to do when you need to change date or time? You invoke setDate() method and what next? Did underlying GObject's property value has been changed as well? No. There's no features like signal emission or simple event notification on PHP level. So, even if you write own callback, no single line of code will trigger it (As a decent framework Midgard supports events).
I wrote midgard_datetime class (DateTime derived) with own underlying C structure and assigned own hooks for it. All in all, at some point I need to know what is the object and what is the property a midgard_datetime holds value for. And this failed because DateTime objects hold own underlying C structures, so when all Zend OO related hooks return void type, you never know what you really get: DateTime structure, midgard_datetime one or maybe mather-in-law? Implementation simplified. But it doesn't mean it became more elegant. I had to register private properties. Yes, this is common for PHP code, but on C level you have armory of possibilities, and had to forget about it.
Examples
In Ragnaroek, you used to print datetime property:
echo $object->metadata->created;
and in vinland, what you wanted to print is an object, so you need to invoke its method:
echo $object->metadata->created->format("c");
midgard_datetime is automagically initialized with DateTimeZone object, so if you need timezone you invoke getTimezone method. Of course, the only one correct timezone for Midgard datetimes is UTC. And you can not change it.
For more flexibility, every DateTime (or derived one) class' object is converted to GValue which holds ISO 8601 formatted string, so ot only objects are "affected" by such conversion. You can pass such objects as Query Builder constraints' values:
$md = new midgard_datetime();
$md->setDate(2009, 01, 02);
$qb = new midgard_query_builder("midgard_article");
$qb->add_constraint("metadata.published", ">", $md);
Performance
I made two simple tests. Both have a loop (100 steps) and assign string datetime. First one uses:
$a = new midgard_article();
$b = $a->title;
and takes from 0,0060 to 0,0080 seconds. This test is almost the same as assigning datetime property the "old" way.
Second one uses midgard_datetime:
$a = new midgard_article();
$d = $a->metadata->created->format("c");
and takes from 0,0180 to 0,0230 seconds.
Looks like midgard_datetime implementation is up to 4 times slower. But as it extends DateTime, there's many features implemented "for free". And if you take into account, that first test requires additional function calls, like strtotime() and date() (to format output), midgard_datetime implementation will be up to 2 times slower. And I think it's not a big problem. midgard_datetime object is created on demand, only when you need to read property. And in practice, you do not need thousands of datetimes available at the same time.
Issues
MySQL doesn't work with constraint used in QB's example. It simply treats string verbatim, so SQL part looks like this:
WHERE metadata_published = '2019-01-01T00:00:00+00:00'
It works, if you remove timezone offset. So I believe fixing the issue is a matter of date formatting.
Also there's no possibility to convert datetime values (returned by collector for example) to midgard_datetime objects. Such values are initialized as GValue values of string type. And this should be fixed by wider midgard timestamp values usage in core.
You can install latest packages, if you would like to try those.
ZEND_ARG_INFO reflections in midgard php bindings
Posted on 2009-01-16 14:42:20 EET.
Yesterday I finished ZEND_ARG_INFO implementation support in PHP bindings for Midgard. I am happy as I closed another ticket, so this nice feature will be also available for Vinland. Yes, I must say this is nice feature. However, at first I was very unhappy how it's implemented in ZE2.
For simple class implmentation you may use ZEND_ARG macros, quite simply.
midgard_connection::open($name):
ZEND_BEGIN_ARG_INFO_EX(arginfo_midgard_connection_open, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
But for dynamic classes, like Mgdschema ones, things are more complicated.
get_by_guid($guid) method:
{ NULL, 0, NULL, 0, 0, 0, 0, 0, 1 },
{ "guid", sizeof("guid")-1, NULL, 0, 0, 0, 0, 0, 0 },
Especially, if you take into account fact, that method's arguments are defined with the same structure as method itself. And of course (as usual), you can not read about this in ZE2 documentation. Just investigate and hack sources.
Anyway, what does it mean for Midgard? Better reflection and nice (almost perfect) way to introspect all Midgard core API via PHP classes.
Let's look at simple example (I used the same code, provided in PHP docs):
$method = new ReflectionMethod('midgard_user', 'password');
$p = $method->getParameters();
foreach ($method->getParameters() as $i => $param)
{
printf(
"-- Parameter #%d: %s {\n".
" Class: %s\n".
" Allows NULL: %s\n".
" Passed to by reference: %s\n".
" Is optional?: %s\n".
"}\n",
$i, // $param->getPosition() can be used from PHP 5.2.3
$param->getName(),
var_export($param->getClass(), 1),
var_export($param->allowsNull(), 1),
var_export($param->isPassedByReference(), 1),
$param->isOptional() ? 'yes' : 'no'
);
}
And the output:
-- Parameter #0: username {
Class: NULL
Allows NULL: false
Passed to by reference: false
Is optional?: no
}
-- Parameter #1: password {
Class: NULL
Allows NULL: false
Passed to by reference: false
Is optional?: no
}
-- Parameter #2: hashtype {
Class: NULL
Allows NULL: false
Passed to by reference: false
Is optional?: yes
}
A real cool thing about such reflection is possibility to create one unified documentation system for code written purely in PHP and for that one written in C extension. If Zend introspection will allow this, we should have much better documentation with less amount of work. And this will be first cool thing provided by Zend :)
Always blame...
Posted on 2008-12-09 13:53:22 EET.
I must say I like to read threads like this. Yes, for me it's kind of endless pleasure to read every single sentence and word in such thread.
Especially this one:
there was a known memory corrupt issue in 5.2.5
Faster MidCOM static files.
Posted on 2008-11-27 22:38:18 EET.
Better late then never, but just today I realized that MidgardEngine directive from Midgard apache module can not work inside Directory one. Not because module has a bug. But because with midgard apache module, apache won't be able to check if it's serving file from such directory. It is the main purpose of midgard module. Serve data from database, not from filesystem.
Of course, MidgardEngine will work in virtaul host scope. But in directory scope -will never work.
How to set MidgardEngine to Off for specific directory then? Use Location. I configured it simply for my virtual host:
<Location /midcom-static/>
MidgardEngine Off
</Location>