Closed (fixed)
Project:
FileField
Version:
6.x-3.x-dev
Component:
Code
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Reporter:
Created:
26 Jan 2009 at 13:30 UTC
Updated:
18 Feb 2009 at 17:20 UTC
Jump to comment: Most recent file
Comments
Comment #1
markus_petrux commentedsorry, minor fix in title.
Comment #2
markus_petrux commentedHere's one possible solution: update the weight of the FileField Meta module so its loaded before the system module, its cron would also be executed before the system cron, and then implement something like this:
Comment #3
markus_petrux commentedhmm... in fact, updating the weight column of FileField Meta in system table would not really be necessary because filefield_meta is already loaded before system module.
So it could be simply fixed implementing the cron task above. A hook_upadate_N could cleanup the table, if needs be (this is alpha code, so...).
Want a patch with just the cron?
Comment #4
markus_petrux commentedWell, here's a patch. It implements hook_cron() and it also includes a hook_update_N() to update the module weight to -1, so the cron here is really executed before system_cron().
I was partically wrong in my previous comment, modules are loaded in weight+filename order, but filename includes the path, so modules* loads before than sites*, hence the update to the module weight is necessary to ensure correct order of cron tasks.
Comment #5
drewish commentedi'd rather not have to change the module weighting... i think a more general solutions would be a hook_cron implementation that deletes records that don't have a corresponding {files} table entry. it wouldn't matter if it happened a cron run later, since it's just clean up.
Comment #6
markus_petrux commentedI also thought about that possible approach, but I dsicarded it because it would require a more complex query (left join or full scan of filefield meta table find matches with file table)... much heavier in terms of performance.
We will be probably using filefield/imagefield for our project, and we can easily manage more than one million images, right from the start, since this is a migration of non-drupal site to D6. So we would prefer an as lighter as possible cron task hammering our DB server just for this cleanup processing.
Comment #7
drewish commented:/ i'm just not into the idea of duplicating core and trying to do it ahead of it...
Comment #8
markus_petrux commentedSorry, I'm not sure what you mean by "duplicating core" :(
Altering the weight of the module is something used by CCK Fieldgroup module. I don't see where's the problem on this.
Ideally, it is core's file API that would have to be patched to affer hooks in file_delete(), for example. But I discarded that since it doesn't look a nice idea to expect for a D6 patch at this point.
Please, consider the performance impact of cleaning the filefield mate table. Do you think of any other way to avoid orphans here? ...if solved by a cron task, we may end up with a hammer that hits the DB every 5 minutes if not optimized.
Comment #9
drewish commentedmy comment on the weighting was misinformed, i'd thought it was changing filefield.module's weight which could have caused compatibility problems with other modules.
okay, then put a @TODO that the code should be moved to hook_file_delete() in D7, and how about an update to clean out any records kicking around from old temp files?
Comment #10
markus_petrux commentedOk, thank you. I'll try to roll and test a patch later today. :-D
Comment #11
markus_petrux commentedThe patch with the @todo note and also an additional query in hook_update_N() to deal with orphans that may exist in the site.
Hope that helps
Comment #12
dopry commentedThere are still potential race conditions for playing with weighting... or errors that prevent the actual deletion in system cron....
I think a good solution would be to change that query to something like...
SELECT * FROM filefield_meta fm LEFT OUTER JOIN files f on fm.fid=f.fid WHERE f.fid IS NULL
which should just select rows that don't have a match in the files table.. I'd normally want to use and EXCEPT statement, but mysql doesn't support it.
.
Comment #13
markus_petrux commenteddopry, the problem with a LEFT JOIN is that it will require a full scan that may take a lot of seconds when you have thousands or a million files, and this is going to hammer the DB at cron intervals.
system_cron() runs the same query, then in the loop it runs file_delete() for each expired temporary file. We need to act before that, or hook into system_cron() / file_delete(). I cannot see how without patching core. :(
Comment #14
dopry commented@markus_petrex: and your other approach leaves the data inconsistent if anything goes wrong in system_cron. I'm telling you simply that if you want to see this patch make it in filefield_meta, you're going to have to do a left join. It's not really open to discussion. It's the only way to keep the db consistent with out on delete cascade... I mean it's done on cron it's not like a user is sitting around waiting on it.
.darrel.
Comment #15
markus_petrux commentedPlease, try to run such an SQL statement when thousands of records are involved. I did (*) and it took forever.
@"It's not really open to discussion": I'm sorry, but I won't push a patch that I will have to patch again on my system. What's the worst thing that can happen if system_cron() goes wrong? Is it possible to find an alternative method to clean up with LEFT JOIN that doesn't mean something hammering the DB at cron intervals?
(*) aside from testing that with Drupal, please see this bulletin board. We have +16 million posts, +1 million topics, etc. Since it's based on phpBB, it is not transactional, therefore it generates orphans here and there. I have a daily cron task that cleans the database. It certainly uses LEFT JOINs, but the process takes 2 hours. It's doable because it's run at midnight, when traffic is low. It wouldn't have been possible if it was spread across 5 minute interval crons. We also run this site (around 2 million pageviews a day), which is being migrated to Drupal. We have more than 1 million images that I plan to port to filefield/imagefield. I cannot run a cron to cleanup orphans in the files table with LEFT JOIN. I hope you can understand my concern.
Comment #16
dopry commentedaye I understand your concerns, but optimizing your db server or the query using the left join is your only option for the proposed approach. It's not up to discussion. I know many sites that use custom cron management tools just to run particular cron jobs at more controlled intervals. I'm designing for data consistency. If you have another solution, I'll be happy to entertain it, but the initial proposal of depending on processing happening later in the cycle that we cannot catch errors for is unacceptable to me. In D7 this will not be as great of an issue since core includes a hook for file deletion.
Comment #17
markus_petrux commentedhmm... have you thought about extending the files table instead of using a separate table for meta data?
Comment #18
dopry commentedfixed in head with left join solution.
Comment #19
markus_petrux commentedIs there such a thing to fine control cron tasks in Drupal? Could you please provide a link or something? Please
Comment #20
dopry commentednormally it is a hack with an include or exclude filter on cron.php and properly configured crontabs. I think something along these lines....
$includes = explode(',', $_GET['includes']);
$excludes = explode(',', $_GET['excludes']);
my_drupal_cron_run($includes, $excludes)....
if (in_array($module, $excludes)) continue;
if (!empty($includes) && !in_array($modules, $includes)) continue;
look at drupal_cron_run for more details...
Comment #21
markus_petrux commentedOh, I see. Thanks for the tip.