diff options
author | Bharat Mediratta <bharat@menalto.com> | 2011-01-09 22:29:26 -0800 |
---|---|---|
committer | Bharat Mediratta <bharat@menalto.com> | 2011-01-09 22:29:26 -0800 |
commit | 65448548637f462ad17c12b149cdb2a169d07026 (patch) | |
tree | 31952af04d038b0e55a0b4c7f1eb246598349996 /modules/server_add/controllers/server_add.php | |
parent | fca6d1254a2aeb95bee15fea4c503e4588fc9f1b (diff) |
Move the directory queue into the database as well, otherwise if you
have too many directories it blows out the task queue and the whole
thing falls over. Fixes #1547.
Diffstat (limited to 'modules/server_add/controllers/server_add.php')
-rw-r--r-- | modules/server_add/controllers/server_add.php | 126 |
1 files changed, 71 insertions, 55 deletions
diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php index 757481d0..15b92cc0 100644 --- a/modules/server_add/controllers/server_add.php +++ b/modules/server_add/controllers/server_add.php @@ -24,6 +24,12 @@ class Server_Add_Controller extends Admin_Controller { $files[] = $path; } + // Clean leftover task rows. There really should be support for this in the task framework + db::build() + ->where("task_id", "NOT IN", db::build()->select("id")->from("tasks")) + ->delete("server_add_entries") + ->execute(); + $item = ORM::factory("item", $id); $view = new View("server_add_tree_dialog.html"); $view->item = $item; @@ -79,17 +85,22 @@ class Server_Add_Controller extends Admin_Controller { access::verify_csrf(); $item = ORM::factory("item", Input::instance()->get("item_id")); - foreach (Input::instance()->post("paths") as $path) { - if (server_add::is_valid_path($path)) { - $paths[] = array($path, null); - } - } - $task_def = Task_Definition::factory() ->callback("Server_Add_Controller::add") ->description(t("Add photos or movies from the local server")) ->name(t("Add from server")); - $task = task::create($task_def, array("item_id" => $item->id, "queue" => $paths)); + $task = task::create($task_def, array("item_id" => $item->id)); + + foreach (Input::instance()->post("paths") as $path) { + if (server_add::is_valid_path($path)) { + $entry = ORM::factory("server_add_entry"); + $entry->path = $path; + $entry->is_directory = 1; + $entry->parent_id = null; + $entry->task_id = $task->id; + $entry->save(); + } + } json::reply( array("result" => "started", @@ -118,7 +129,7 @@ class Server_Add_Controller extends Admin_Controller { /** * This is the task code that adds photos and albums. It first examines all the target files - * and creates a set of Server_Add_File_Models, then runs through the list of models and adds + * and creates a set of Server_Add_Entry_Models, then runs through the list of models and adds * them one at a time. */ static function add($task) { @@ -128,6 +139,7 @@ class Server_Add_Controller extends Admin_Controller { switch ($mode) { case "init": $task->set("mode", "build-file-list"); + $task->set("dirs_scanned", 0); $task->percent_complete = 0; $task->status = t("Starting up"); batch::start(); @@ -136,58 +148,63 @@ class Server_Add_Controller extends Admin_Controller { case "build-file-list": // 0% to 10% // We can't fit an arbitrary number of paths in a task, so store them in a separate table. // Don't use an iterator here because we can't get enough control over it when we're dealing - // with a deep hierarchy and we don't want to go over our time quota. The queue is in the - // form [path, parent_id] where the parent_id refers to another Server_Add_File_Model. We - // have this extra level of abstraction because we don't know its Item_Model id yet. - $queue = $task->get("queue"); + // with a deep hierarchy and we don't want to go over our time quota. $paths = unserialize(module::get_var("server_add", "authorized_paths")); + $dirs_scanned = $task->get("dirs_scanned"); + while (microtime(true) - $start < 0.5) { + // Process every directory that doesn't yet have a parent id, these are the + // paths that we're importing. + $entry = ORM::factory("server_add_entry") + ->where("task_id", "=", $task->id) + ->where("is_directory", "=", 1) + ->where("checked", "=", 0) + ->order_by("id", "ASC") + ->find(); - while ($queue && microtime(true) - $start < 0.5) { - list($file, $parent_entry_id) = array_shift($queue); - // Ignore the staging directories as directories to be imported. - if (empty($paths[$file])) { - $entry = ORM::factory("server_add_file"); - $entry->task_id = $task->id; - $entry->file = $file; - $entry->parent_id = $parent_entry_id; - $entry->save(); - $entry_id = $entry->id; - } else { - $entry_id = null; - } + if ($entry->loaded()) { + // Ignore the staging directories as directories to be imported. + if (!empty($paths[$entry->path])) { + $entry->delete(); + } - $file = preg_replace("/(\*|\?|\[)/", "[$1]", $file); - foreach (glob("$file/*") as $child) { - if (is_dir($child)) { - $queue[] = array($child, $entry_id); - } else { - $ext = strtolower(pathinfo($child, PATHINFO_EXTENSION)); - if (in_array($ext, array("gif", "jpeg", "jpg", "png", "flv", "mp4", "m4v")) && - filesize($child) > 0) { - $child_entry = ORM::factory("server_add_file"); - $child_entry->task_id = $task->id; - $child_entry->file = $child; - $child_entry->parent_id = $entry_id; - $child_entry->save(); + $path = preg_replace("/(\*|\?|\[)/", "[$1]", $entry->path); + foreach (glob("$path/*") as $child_path) { + if (!is_dir($child_path)) { + $ext = strtolower(pathinfo($child_path, PATHINFO_EXTENSION)); + if (!in_array($ext, array("gif", "jpeg", "jpg", "png", "flv", "mp4", "m4v")) || + !filesize($child_path)) { + // Not importable, skip it. + continue; + } } + + $child_entry = ORM::factory("server_add_entry"); + $child_entry->task_id = $task->id; + $child_entry->path = $child_path; + $child_entry->parent_id = $entry->id; // null if the parent was a staging dir + $child_entry->is_directory = is_dir($child_path); + $child_entry->save(); } + + // We've processed this entry, mark it as done. + $entry->checked = 1; + $entry->save(); } + $dirs_scanned++; } // We have no idea how long this can take because we have no idea how deep the tree // hierarchy rabbit hole goes. Leave ourselves room here for 100 iterations and don't go // over 10% in percent_complete. - $task->set("queue", $queue); + $task->set("dirs_scanned", $dirs_scanned); $task->percent_complete = min($task->percent_complete + 0.1, 10); - $task->status = t2( - "Found one file", "Found %count files", - ORM::factory("server_add_file")->where("task_id", "=", $task->id)->count_all()); + $task->status = t2("Scanned one directory", "Scanned %count directories", $dirs_scanned); - if (!$queue) { + if (!$entry->loaded()) { $task->set("mode", "add-files"); $task->set( "total_files", - ORM::factory("server_add_file")->where("task_id", "=", $task->id)->count_all()); + ORM::factory("server_add_entry")->where("task_id", "=", $task->id)->count_all()); $task->percent_complete = 10; } break; @@ -199,7 +216,7 @@ class Server_Add_Controller extends Admin_Controller { // Ordering by id ensures that we add them in the order that we created the entries, which // will create albums first. Ignore entries which already have an Item_Model attached, // they're done. - $entries = ORM::factory("server_add_file") + $entries = ORM::factory("server_add_entry") ->where("task_id", "=", $task->id) ->where("item_id", "IS", null) ->order_by("id", "ASC") @@ -218,16 +235,16 @@ class Server_Add_Controller extends Admin_Controller { // Look up the parent item for this entry. By now it should exist, but if none was // specified, then this belongs as a child of the current item. - $parent_entry = ORM::factory("server_add_file", $entry->parent_id); + $parent_entry = ORM::factory("server_add_entry", $entry->parent_id); if (!$parent_entry->loaded()) { $parent = ORM::factory("item", $task->get("item_id")); } else { $parent = ORM::factory("item", $parent_entry->item_id); } - $name = basename($entry->file); + $name = basename($entry->path); $title = item::convert_filename_to_title($name); - if (is_dir($entry->file)) { + if ($entry->is_directory) { $album = ORM::factory("item"); $album->type = "album"; $album->parent_id = $parent->id; @@ -243,7 +260,7 @@ class Server_Add_Controller extends Admin_Controller { $photo = ORM::factory("item"); $photo->type = "photo"; $photo->parent_id = $parent->id; - $photo->set_data_file($entry->file); + $photo->set_data_file($entry->path); $photo->name = $name; $photo->title = $title; $photo->owner_id = $owner_id; @@ -253,7 +270,7 @@ class Server_Add_Controller extends Admin_Controller { $movie = ORM::factory("item"); $movie->type = "movie"; $movie->parent_id = $parent->id; - $movie->set_data_file($entry->file); + $movie->set_data_file($entry->path); $movie->name = $name; $movie->title = $title; $movie->owner_id = $owner_id; @@ -264,12 +281,12 @@ class Server_Add_Controller extends Admin_Controller { // process. But just in, case.. set this to a non-null value so that we skip this // entry. $entry->item_id = 0; - $task->log("Skipping unknown file type: $entry->file"); + $task->log("Skipping unknown file type: {$entry->path}"); } } catch (Exception $e) { // This can happen if a photo file is invalid, like a BMP masquerading as a .jpg $entry->item_id = 0; - $task->log("Skipping invalid file: $entry->file"); + $task->log("Skipping invalid file: {$entry->file}"); } } @@ -288,10 +305,9 @@ class Server_Add_Controller extends Admin_Controller { $task->done = true; $task->state = "success"; $task->percent_complete = 100; - db::build() - ->delete("server_add_files") + ORM::factory("server_add_entry") ->where("task_id", "=", $task->id) - ->execute(); + ->delete_all(); message::info(t2("Successfully added one photo / album", "Successfully added %count photos / albums", $task->get("completed_files"))); |