CodeIgniter Forums
DataMapper 1.6.0 - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Libraries & Helpers (https://forum.codeigniter.com/forumdisplay.php?fid=22)
+--- Thread: DataMapper 1.6.0 (/showthread.php?tid=11358)



DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]Murodese[/eluser]
Very few records - 1-5 on each table.


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]Paul Apostol[/eluser]
Hello,
The only requested thing, as usual for me, is the joining table prefix.
Do you think that replacing in "_get_relationship_table" the line:
Code:
$relationship_table = (empty($this->join_prefix)) ? $this->prefix . $relationship_table : $this->join_prefix . $relationship_table;
with:
Code:
if(is_array( $this->join_prefix)){
    $relationship_table = (empty($this->join_prefix[strtolower($model)])) ? $this->prefix . $relationship_table : $this->join_prefix[strtolower($model)] . $relationship_table;
} else{
    $relationship_table = (empty($this->join_prefix)) ? $this->prefix . $relationship_table : $this->join_prefix . $relationship_table;
        }
will be OK?
That will allow for the people who wants to use different prefixes for the joining table to use an alternative declaration (I'm using it inside the model):
Code:
var $join_prefix = array('model_name'=>'join_prefix')
The rest is awesome. This library shrink the development time at half.
Thank you,
Paul


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]stensi[/eluser]
Paul, unfortunately at the moment, if you want to have different prefix and join_prefix settings on a per model basis, you can't use the datamapper config file, or at least have the prefix settings put in it as they apply globally to all DataMapper models (removing the settings from the config will force it to use what's set in your model).

In the next version though I'll be adding the ability to have custom config files per model. For example, there's the DataMapper config that applies to all of them, but then if there's a config file named the same as your model,such as a "user" config for a "User" model, then the user config settings get loaded over the top of the global datamapper config settings.

I should have time today to put together that test suite I mentioned. I'm not just looking at speed though as there should have been some memory improvements too. I'll be interested to see the results!


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]Paul Apostol[/eluser]
Thanks stensi,
I know how it works. I'll keep patching that function on each new version.


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]stensi[/eluser]
Actually, now that I think about it. I should be doing the following in the constructor during the reading of the config file settings:

Code:
// Load stored config settings
foreach (DataMapper::$config as $key => $value)
{
    if (empty($this->{$key}))
    {
        $this->{$key} = $value;
    }
}

That should solve the issue as if it's already set in your model, it will keep that setting, thus, per model prefixing. No extra config files needed then. However, you'll need to blank the following variables in the datamapper.php library or they'll never load from the config:

Code:
var $error_prefix = '';
var $error_suffix = '';
var $created_field = '';
var $updated_field = '';

Does that suit your needs ok?






_________________________

UPDATE:

Well, this is both interesting and worrying, lol! I have the performance test results and it looks like the latest version has a memory issue :down:

Here's the setup. I'm using the groups, groups_users and users tables from the DataMapper Database Schema.

groups table has 100 records.
users table has 1000 records.
groups_users table has 1000 records.

The users were randomly assigned to a group and it ended up that each group had from 4 to 22 users (so they all have relations to users).

The code I benchmarked get() with, keeping in mind that there are many records for it to process:

Code:
$this->benchmark->mark('code_start');

$g = new Group();
$g->get();

foreach ($g->all as $group)
{
    echo $group->name . ' has these users:<br />';

    $group->user->get();

    foreach ($group->user->all as $user)
    {
        echo '&nbsp;&nbsp;&nbsp;&nbsp;' . $user->username . '<br />';
    }
}

$this->benchmark->mark('code_end');

echo $this->benchmark->elapsed_time('code_start', 'code_end');


And the results, showing the execution time of the above code and memory consumption.


DataMapper 1.4.5 : stress test get()

12.7795 2,386,920 bytes
12.3789 2,390,032 bytes
12.3302 2,386,920 bytes
12.3157 2,386,920 bytes
12.8587 2,386,920 bytes


DataMapper 1.5.0 : stress test get()

10.7321 11,158,720 bytes
10.8895 11,158,432 bytes
10.7776 11,158,912 bytes
10.7482 11,158,720 bytes
10.8656 11,158,720 bytes


As you can see, the new version is roughly 2 seconds faster but it seems there's a memory issue!

Note: The speed is relative to the processing power of the test server. It's not all that powerful so I expect this would go much faster on my dedicated server.

I'll be spending today tracking down the cause and then releasing a fixed version which should end up having the same memory usage as version 1.4.5 but the speed improvements of 1.5.0!


UPDATE:

What a guess!

The first thing I checked turned out to be the cause of the memory issue. The change I did in replacing the related array with a parent object that is a reference is what did it. I suspected that would be the cause but am still not sure why it chewed up so much memory.

I'll see if I can setup the object reference differently, otherwise I'll just revert it back to an array.


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]stensi[/eluser]
DataMapper 1.4.5 : stress test get()

12.7795 2,386,920 bytes
12.3789 2,390,032 bytes
12.3302 2,386,920 bytes
12.3157 2,386,920 bytes
12.8587 2,386,920 bytes


DataMapper 1.5.0 : stress test get()

10.7321 11,158,720 bytes
10.8895 11,158,432 bytes
10.7776 11,158,912 bytes
10.7482 11,158,720 bytes
10.8656 11,158,720 bytes


DataMapper 1.5.1 : stress test get()

10.5575 2,487,192 bytes
10.6383 2,483,696 bytes
10.5385 2,483,696 bytes
10.5081 2,483,696 bytes
10.3400 2,483,696 bytes


With version 1.5.1, it looks like I sped things up just a tiny bit more as well as fixing the memory issue. Sure, it ends up using roughly 100k more memory than version 1.4.5 but the speed improvement more than makes up for that and when you start using other methods, such as save(), version 1.5.1 ends up doing much better with memory usage on top of the speed. See the test below.


I adjusted the test code to the following to test save():

Code:
$this->benchmark->mark('code_start');

$g = new Group();
$g->get();

foreach ($g->all as $group)
{
    echo $group->name . ' has these users:<br />';

    $group->user->get();

    foreach ($group->user->all as $user)
    {
        echo '&nbsp;&nbsp;&nbsp;&nbsp;' . $user->username . '<br />';

        // Change username to ensure database update
        $user->username = substr(md5(uniqid(rand(), true)), 0, 10);

        // Save user
        $user->save();
    }
}

$this->benchmark->mark('code_end');

echo $this->benchmark->elapsed_time('code_start', 'code_end');


And the results.


DataMapper 1.4.5 : stress test save()

32.6919 4,585,448 bytes
31.5780 4,588,320 bytes
31.8926 4,585,448 bytes
32.7084 4,588,328 bytes
31.7846 4,585,448 bytes


DataMapper 1.5.1 : stress test save()

22.9622 3,290,672 bytes
24.1194 3,287,776 bytes
23.0845 3,287,776 bytes
26.6848 3,287,776 bytes
24.1903 3,287,776 bytes


As you can see, with the improvements made to validation and other areas, version 1.5.1 is a hell of a lot faster and uses over 1MB less memory during save() than version 1.4.5!

Again, note that my test server isn't very fast (running off a USB) so on a better server you'll see much quicker times working with that many records.

Now, I just need to update the documentation and then I'll put version 1.5.1 up :-)


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]OverZealous[/eluser]
Wow, stensi, that's awesome. I'm glad to see these improvements. Once again, I feel quite lucky to have stumbled upon DM when starting my latest project. Major development time savings, and as time goes on, pretty darn fast, to boot!

How did you decide to fix the memory issue? Did you try using assign-by-reference? (ie: $this->parent =& $parent_object)

Now, I just need to set aside a day to upgrade to CI 1.7 and DM 1.5.1 ;-P


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]stensi[/eluser]
Version 1.5.1 has been released!

View the Change Log to see what's changed.

Basically, the memory issue has been fixed and the config file settings can now be correctly overridden by setting the values directly in your models.

Enjoy :-)


@OverZealous.com: PHP5 assigns objects by reference by default so the & is not necessary.

You can test this by doing:

Code:
$u1 = new User();
$u1->get();

$u2 = $u1; // notice no =&

// Let's pretend the username is: foo
echo $u1->username . '<br />'; // outputs: foo
echo $u2->username . '<br />'; // outputs: foo

echo '<br />';

// Change username in u2
$u2->username = 'bar';

echo $u1->username . '<br />'; // outputs: bar (in PHP5, PHP4 will remain as foo unless =& was used)
echo $u2->username . '<br />'; // outputs: bar

Even so, I tried testing with both = and =& and in both cases the memory issue occurred. I solved it by reverting it back to an array containing the parents id and model name.

It's well worth the upgrade! :-)


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]OverZealous[/eluser]
Right, I knew that. Smile I wonder why it would increase the memory, though? Not really a big issue, for now.

Update: From what I can tell through my quick skimming online, GC in PHP is, effectively, stupid. It is unable to determine that two objects which point to each other, yet have no other path of accessibility, need to be GCd. Therefore, the act of pointing Object A ($parent) at Object B ($child), and pointing $child back to $parent, means that those objects will not be collected until the script exits, or one of those two items are manually removed.

The only solution would be to create some kind of "destroy" method that was manually called by the application, or to hand unset $parent in the app.


DataMapper 1.6.0 - El Forum - 12-03-2008

[eluser]Murodese[/eluser]
Brilliant, thanks Stensi Smile