protected function getConnection(DataSourceMetaData $datasource)
 {
     $transaction = TransactionManager::getInstance()->getTransaction($datasource->name);
     $connectionName = $transaction->assembleResourceName(get_class($datasource), $datasource->name);
     $connection = $transaction->findResource($connectionName);
     if (!isset($connection)) {
         $connection = $this->getExtension('initializeConnection')->initialize($this, $datasource);
         if (!$datasource->temporary) {
             $transaction->registerResource($connectionName, $connection);
             $transaction->registerActionCallback(new ConnectionTransactionActionCallback($datasource->name));
         }
     }
     return $connection;
 }
Example #2
0
 /**
  * blcLink::save()
  * Save link data to DB.
  *
  * @return bool True if saved successfully, false otherwise.
  */
 function save()
 {
     global $wpdb, $blclog;
     /** @var wpdb $wpdb */
     if (!$this->valid()) {
         return false;
     }
     //A link can't be broken and treated as a warning at the same time.
     if ($this->broken && $this->warning) {
         $this->warning = false;
     }
     //Make a list of fields to be saved and their values in DB format
     $values = array();
     foreach ($this->field_format as $field => $format) {
         $values[$field] = $this->{$field};
     }
     $values = $this->to_db_format($values);
     if ($this->is_new) {
         TransactionManager::getInstance()->commit();
         //BUG: Technically, there should be a 'LOCK TABLES wp_blc_links WRITE' here. In fact,
         //the plugin should probably lock all involved tables whenever it parses something, lest
         //the user (ot another plugin) modify the thing being parsed while we're working.
         //The problem with table locking, though, is that parsing takes a long time and having
         //all of WP freeze while the plugin is working would be a Bad Thing. Food for thought.
         //Check if there's already a link with this URL present
         $q = $wpdb->prepare("SELECT link_id FROM {$wpdb->prefix}blc_links WHERE url = %s", $this->url);
         $existing_id = $wpdb->get_var($q);
         if (!empty($existing_id)) {
             //Dammit.
             $this->link_id = $existing_id;
             $this->is_new = false;
             return true;
         }
         //Insert a new row
         $q = sprintf("INSERT INTO {$wpdb->prefix}blc_links( %s ) VALUES( %s )", implode(', ', array_keys($values)), implode(', ', array_values($values)));
         //FB::log($q, 'Link add query');
         $blclog->debug(__CLASS__ . ':' . __FUNCTION__ . ' Adding a new link. SQL query:' . "\n", $q);
         $rez = $wpdb->query($q) !== false;
         if ($rez) {
             $this->link_id = $wpdb->insert_id;
             $blclog->debug(__CLASS__ . ':' . __FUNCTION__ . ' Database record created. ID = ' . $this->link_id);
             //FB::info($this->link_id, "Link added");
             //If the link was successfully saved then it's no longer "new"
             $this->is_new = false;
         } else {
             $blclog->error(__CLASS__ . ':' . __FUNCTION__ . ' Error adding link', $this->url);
             //FB::error($wpdb->last_error, "Error adding link {$this->url}");
         }
         return $rez;
     } else {
         if ($this->isOptionLinkChanged !== true) {
             TransactionManager::getInstance()->start();
         }
         $this->isOptionLinkChanged = false;
         //Generate the field = dbvalue expressions
         $set_exprs = array();
         foreach ($values as $name => $value) {
             $set_exprs[] = "{$name} = {$value}";
         }
         $set_exprs = implode(', ', $set_exprs);
         //Update an existing DB record
         $q = sprintf("UPDATE {$wpdb->prefix}blc_links SET %s WHERE link_id=%d", $set_exprs, intval($this->link_id));
         //FB::log($q, 'Link update query');
         $blclog->debug(__CLASS__ . ':' . __FUNCTION__ . ' Updating a link. SQL query:' . "\n", $q);
         $rez = $wpdb->query($q) !== false;
         if ($rez) {
             //FB::log($this->link_id, "Link updated");
             $blclog->debug(__CLASS__ . ':' . __FUNCTION__ . ' Link updated.');
         } else {
             $blclog->error(__CLASS__ . ':' . __FUNCTION__ . ' Error updating link', $this->url);
             //FB::error($wpdb->last_error, "Error updating link {$this->url}");
         }
         return $rez;
     }
 }
 /**
  * Parse the container for links and save the results to the DB.
  *
  * @return void
  */
 function synch()
 {
     //FB::log("Parsing {$this->container_type}[{$this->container_id}]");
     //Remove any existing link instance records associated with the container
     $this->delete_instances();
     //Load the wrapped object, if not done already
     $this->get_wrapped_object();
     //FB::log($this->fields, "Parseable fields :");
     //Iterate over all parse-able fields
     foreach ($this->fields as $name => $format) {
         //Get the field value
         $value = $this->get_field($name);
         if (empty($value)) {
             //FB::log($name, "Skipping empty field");
             continue;
         }
         //FB::log($name, "Parsing field");
         //Get all parsers applicable to this field
         $parsers = blcParserHelper::get_parsers($format, $this->container_type);
         //FB::log($parsers, "Applicable parsers");
         if (empty($parsers)) {
             continue;
         }
         $base_url = $this->base_url();
         $default_link_text = $this->default_link_text($name);
         //Parse the field with each parser
         foreach ($parsers as $parser) {
             //FB::log("Parsing $name with '{$parser->parser_type}' parser");
             $found_instances = $parser->parse($value, $base_url, $default_link_text);
             //FB::log($found_instances, "Found instances");
             $transactionManager = TransactionManager::getInstance();
             $transactionManager->start();
             //Complete the link instances by adding container info, then save them to the DB.
             foreach ($found_instances as $instance) {
                 $instance->set_container($this, $name);
                 $instance->save();
             }
             $transactionManager->commit();
         }
     }
     $this->mark_as_synched();
 }
Example #4
0
 /**
  * The main worker function that does all kinds of things.
  *
  * @return void
  */
 function work()
 {
     global $blclog;
     //Close the session to prevent lock-ups.
     //PHP sessions are blocking. session_start() will wait until all other scripts that are using the same session
     //are finished. As a result, a long-running script that unintentionally keeps the session open can cause
     //the entire site to "lock up" for the current user/browser. WordPress itself doesn't use sessions, but some
     //plugins do, so we should explicitly close the session (if any) before starting the worker.
     if (session_id() != '') {
         session_write_close();
     }
     if (!$this->acquire_lock()) {
         //FB::warn("Another instance of BLC is already working. Stop.");
         $blclog->info('Another instance of BLC is already working. Stop.');
         return;
     }
     if ($this->server_too_busy()) {
         //FB::warn("Server is too busy. Stop.");
         $blclog->warn('Server load is too high, stopping.');
         return;
     }
     $this->start_timer();
     $blclog->info('work() starts');
     $max_execution_time = $this->conf->options['max_execution_time'];
     /*****************************************
     						Preparation
     		******************************************/
     // Check for safe mode
     if (blcUtility::is_safe_mode()) {
         // Do it the safe mode way - obey the existing max_execution_time setting
         $t = ini_get('max_execution_time');
         if ($t && $t < $max_execution_time) {
             $max_execution_time = $t - 1;
         }
     } else {
         // Do it the regular way
         @set_time_limit($max_execution_time * 2);
         //x2 should be plenty, running any longer would mean a glitch.
     }
     //Don't stop the script when the connection is closed
     ignore_user_abort(true);
     //Close the connection as per http://www.php.net/manual/en/features.connection-handling.php#71172
     //This reduces resource usage.
     //(Disable when debugging or you won't get the FirePHP output)
     if (!headers_sent() && (defined('DOING_AJAX') && constant('DOING_AJAX')) && (!defined('BLC_DEBUG') || !constant('BLC_DEBUG'))) {
         @ob_end_clean();
         //Discard the existing buffer, if any
         header("Connection: close");
         ob_start();
         echo 'Connection closed';
         //This could be anything
         $size = ob_get_length();
         header("Content-Length: {$size}");
         ob_end_flush();
         // Strange behaviour, will not work
         flush();
         // Unless both are called !
     }
     //Load modules for this context
     $moduleManager = blcModuleManager::getInstance();
     $moduleManager->load_modules('work');
     $target_usage_fraction = $this->conf->get('target_resource_usage', 0.25);
     //Target usage must be between 1% and 100%.
     $target_usage_fraction = max(min($target_usage_fraction, 1), 0.01);
     /*****************************************
     				Parse posts and bookmarks
     		******************************************/
     $orphans_possible = false;
     $still_need_resynch = $this->conf->options['need_resynch'];
     if ($still_need_resynch) {
         //FB::log("Looking for containers that need parsing...");
         $max_containers_per_query = 50;
         $start = microtime(true);
         $containers = blcContainerHelper::get_unsynched_containers($max_containers_per_query);
         $get_containers_time = microtime(true) - $start;
         while (!empty($containers)) {
             //FB::log($containers, 'Found containers');
             $this->sleep_to_maintain_ratio($get_containers_time, $target_usage_fraction);
             foreach ($containers as $container) {
                 $synch_start_time = microtime(true);
                 //FB::log($container, "Parsing container");
                 $container->synch();
                 $synch_elapsed_time = microtime(true) - $synch_start_time;
                 $blclog->info(sprintf('Parsed container %s[%s] in %.2f ms', $container->container_type, $container->container_id, $synch_elapsed_time * 1000));
                 //Check if we still have some execution time left
                 if ($this->execution_time() > $max_execution_time) {
                     //FB::log('The allotted execution time has run out');
                     blc_cleanup_links();
                     $this->release_lock();
                     return;
                 }
                 //Check if the server isn't overloaded
                 if ($this->server_too_busy()) {
                     //FB::log('Server overloaded, bailing out.');
                     blc_cleanup_links();
                     $this->release_lock();
                     return;
                 }
                 //Intentionally slow down parsing to reduce the load on the server. Basically,
                 //we work $target_usage_fraction of the time and sleep the rest of the time.
                 $this->sleep_to_maintain_ratio($synch_elapsed_time, $target_usage_fraction);
             }
             $orphans_possible = true;
             $start = microtime(true);
             $containers = blcContainerHelper::get_unsynched_containers($max_containers_per_query);
             $get_containers_time = microtime(true) - $start;
         }
         //FB::log('No unparsed items found.');
         $still_need_resynch = false;
     } else {
         //FB::log('Resynch not required.');
     }
     /******************************************
     				    Resynch done?
     		*******************************************/
     if ($this->conf->options['need_resynch'] && !$still_need_resynch) {
         $this->conf->options['need_resynch'] = $still_need_resynch;
         $this->conf->save_options();
     }
     /******************************************
     				    Remove orphaned links
     		*******************************************/
     if ($orphans_possible) {
         $start = microtime(true);
         $blclog->info('Removing orphaned links.');
         blc_cleanup_links();
         $get_links_time = microtime(true) - $start;
         $this->sleep_to_maintain_ratio($get_links_time, $target_usage_fraction);
     }
     //Check if we still have some execution time left
     if ($this->execution_time() > $max_execution_time) {
         //FB::log('The allotted execution time has run out');
         $blclog->info('The allotted execution time has run out.');
         $this->release_lock();
         return;
     }
     if ($this->server_too_busy()) {
         //FB::log('Server overloaded, bailing out.');
         $blclog->info('Server load too high, stopping.');
         $this->release_lock();
         return;
     }
     /*****************************************
     						Check links
     		******************************************/
     $max_links_per_query = 30;
     $start = microtime(true);
     $links = $this->get_links_to_check($max_links_per_query);
     $get_links_time = microtime(true) - $start;
     while ($links) {
         $this->sleep_to_maintain_ratio($get_links_time, $target_usage_fraction);
         //Some unchecked links found
         //FB::log("Checking ".count($links)." link(s)");
         $blclog->info("Checking " . count($links) . " link(s)");
         //Randomizing the array reduces the chances that we'll get several links to the same domain in a row.
         shuffle($links);
         $transactionManager = TransactionManager::getInstance();
         $transactionManager->start();
         foreach ($links as $link) {
             //Does this link need to be checked? Excluded links aren't checked, but their URLs are still
             //tested periodically to see if they're still on the exclusion list.
             if (!$this->is_excluded($link->url)) {
                 //Check the link.
                 //FB::log($link->url, "Checking link {$link->link_id}");
                 $link->check(true);
             } else {
                 //FB::info("The URL {$link->url} is excluded, skipping link {$link->link_id}.");
                 $link->last_check_attempt = time();
                 $link->save();
             }
             //Check if we still have some execution time left
             if ($this->execution_time() > $max_execution_time) {
                 //FB::log('The allotted execution time has run out');
                 $blclog->info('The allotted execution time has run out.');
                 $this->release_lock();
                 return;
             }
             //Check if the server isn't overloaded
             if ($this->server_too_busy()) {
                 //FB::log('Server overloaded, bailing out.');
                 $blclog->info('Server load too high, stopping.');
                 $this->release_lock();
                 return;
             }
         }
         $transactionManager->commit();
         $start = microtime(true);
         $links = $this->get_links_to_check($max_links_per_query);
         $get_links_time = microtime(true) - $start;
     }
     //FB::log('No links need to be checked right now.');
     $this->release_lock();
     $blclog->info('work(): All done.');
     //FB::log('All done.');
 }
    public function abort() {
        $transaction = TransactionManager::getInstance()->getTransaction($this->datasourceName);
        $transaction->rollback();

        parent::abort();
    }