-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Persistent Mux in the extension #18
Comments
Sounds great, I think we could have PersistentMux or something that load routes from a definition file. |
That would be good too. How do you imagine the definition file? Some notation language (JSON, YAML, etc), using the PHP Mux classes or a simple array? |
the definition file could be a simple php script that returns Mux object because we need to compile the patterns for PCRE routes. and we can cache the Mux object (zval pointer) in the persistent memory) theoretically. |
Right, this was my intention with the |
yeah, and a config key can be added for checking the fstat or not. if the filemtime is greater, then we do reload the definition file. that will be easier for development. |
It would be nice. But for a production environment it would be better if not check the filemtime, similar of the |
yeah that's right, just like |
to gain more, we could reduce the function calls to one statement, something like: $route = Pux\PersistentMux::dispatch('app_routes', 'routes.php', $_SERVER['PATH_INFO']); and the parameters can be read as "get persistent mux from key 'app_routes', if no, read the definition file from 'routes.php', then dispatch path with PATH_INFO) |
Awesome! The app will fly. |
Yeah! I am so excited |
Rename Pux\PersistentMux to Pux\PersistentDispatcher seems like better? |
I saw you have |
yeah right |
NOTE: This seems need to allocate a global array (internally) which will be much easier to maintain the hash table. Also there is a PZVAL_LOCK, which seems like for locking persistent zval. |
|
HashTable can be implemented in:
And can be initilized in the MINIT function:
|
currently working on https://github.com/c9s/Pux/tree/persistent-dispatcher branch |
Damn, this was fast. Nice to see some code coming for that. 👍 |
Wondering the difference between When using |
I am not very good with PHP extensions. I can read and understand the code, I wrote some small tests, but nothing decent. But, I looked few extensions to see how they manage the persistent connections and seems all them use the |
yeah, seems like the only way to do it is to use the |
As I said before, I am really bad with php extensions, but I started a When I have some decent code to show I will push to my fork and probably I hope to have something more concrete tomorrow or in the weekend. |
I've done the store_mux functionality, I think we need to implement a basic function to archive that. please see #24 for more details. |
So I just got the basic persistent functions work, now we have in-process persistent mux object! <?php
echo "process: " , getmypid() , "\n";
$mux = pux_fetch_mux('app');
if ( $mux ) {
echo "Mux Fetched!\n";
} else {
$mux = new Pux\Mux;
echo "Mux Created!\n";
pux_store_mux('app', $mux);
echo "Mux Stored!\n";
} Please see if this works for you! |
Refactored to 88c2c4d, so we can reuse the static functions in our dispatch function. I think the fastest way to call is: $route = pux_persistent_dispatch('app', 'routes.php', $_SERVER['PATH_INFO']);
$route = pux_persistent_dispatch('app', 'routes.php'); // dispatch SERVER['PATH_INFO'] by default, so we don't pass extra parameters. |
The next thing we need to implement is the "require" mech. currently I found |
|
When I was working on that yesterday I decided to expect a function instead of the string. My plan is call the function and expect a mux instance. Version 2 can improve to load the file. So, basically my API will looks like: Pux\Dispatcher\PersistentDispatcher::dispatch('alias', function() { return include 'routes.php'; }, '/foo'); In this case I was wondering in move the function to the last parameter... Btw, really nice to have the methods in place. 👍 |
Also, having the function allow people to lazy instantiate the mux inline without have a file to it, or even call a function somewhere else. Ie // Lazy mux instance
Pux\Dispatcher\PersistentDispatcher::dispatch('alias', function() {
$mux = new Pux\Mux();
// ...
return $mux;
}, '/foo');
// Using OO
class MyAppRouting {
public function routes() {
// ...
return $mux;
}
}
$routing = new MyAppRouting();
Pux\Dispatcher\PersistentDispatcher::dispatch('alias', function() use (&$routing) {
return $routing->routes();
}, '/foo'); |
OK Just found a way to require file from extension. |
I think it's fine to also have a OO style interface to do that To gain the performance, function call is faster. it's because static method call require class entry lookup. We need to first implement the function, then reuse the function in our static method for our OO style interface. Thoughts? |
yeah, I also like the idea of lazy initialization. |
but If we want to use closure as lazy evaluation, putting the request URI as the third parameter might not be a good choice. |
Hmmm, little ugly how the include works, but if it is the way, what can we do?! I am not a fan of functions on extensions. As your extension use everything with classes, I would suggest to keep all in classes with the And I agree having the URI as 3rd param will not be nice with callable. So the new signature would be: |
I guess it's not the ugliest one. =p I pushed some code that does the "require" which is actually "eval" some code. also I would like to provide both OO interface and function interface. users may extend from the dispatcher class to extend more functionality. and function call interface for faster call, which is with a prefix "pux_", so don't worry about the naming conflict. In your static method call synopsis, I think Pux\Dispatcher\PersistentDispatcher::dispatch($uri, $alias, callbable $func); If we want to make |
Done!
|
After some testing, I found a zend engine problem, that is... even you use |
So.. the solution will be much more complex - serialize the object just like apc do and store it in persistent memory. |
If I am not wrong, you have to use |
Actually the reference counting is done by I've tried, that doesn't work, reference counting only works in the same On Sun, Jan 19, 2014 at 1:19 AM, Juan Basso notifications@github.comwrote:
Best Regards, Yo-An Lin |
I thought so too, but unfortunately it's not. also the hash table in zend object is not persistent. so we need to serialize them. |
I asked on the php internal mailing list and have some conclusions:
|
Joe posted some related links of copying HashTable from APC: https://github.com/krakjoe/apcu/blob/simplify/apc_cache.c#L1164 https://github.com/krakjoe/apcu/blob/simplify/apc_cache.c#L1309 Perhaps we can copy the HashTable from zend object and store it back when fetching it from persistent_list. |
Some related discussion: And zend object documentation: |
Interesting. At least has a workaround like APC does :) |
Just pushed some code c1ff18f to create a persistent hash of the properties. but still segmentation fault when destroying resource list entry. |
Alright... I have been stranded by the zend garbage collection... zzz The new idea comes from my head. just forgot about zval or zend object, let's convert routes into pure C struct and make it persistent, I guess it will be much easier than keeping a zend object or zend array persistent. Another benefit is that while dispatching, we can simply iterate the lightweight fast linked list without using zend_hash struct and convert these zval(s) in every loop. Using pure C struct can be even faster. stay tuned. =] |
Just fixed the memory leak and it works now! :D Tested the performance and it's around 1.2x~1.6x faster now. Will open another issue for the OO style persistent dispatch. |
To improve even more the performance, you can make create an alias for the Mux class and it be stored in the extension persistent memory.
For web requests, the first request will load from the compiled router file. For subsequent request it can use the persisted object in memory. It will avoid file access to read the compiled file and re-load all the objects for every request.
You can make something like:
Something like that. Thoughts?
The text was updated successfully, but these errors were encountered: