| 1 |
<?php |
<?php |
| 2 |
// $Id: xapian.module,v 1.10.2.7 2009/02/05 23:37:27 jeremy Exp $ |
// $Id: xapian.module,v 1.10.2.8 2009/02/06 18:27:05 jeremy Exp $ |
| 3 |
|
|
| 4 |
/** |
/** |
| 5 |
* @file |
* @file |
| 8 |
* Initial Development and sample view code by Lachlan Gunn - http://drupal.org/user/277696 |
* Initial Development and sample view code by Lachlan Gunn - http://drupal.org/user/277696 |
| 9 |
* Core patch, tighter drupal integration, adherance to drupal standards, |
* Core patch, tighter drupal integration, adherance to drupal standards, |
| 10 |
* making ready for release by Simon Lindsay - http://drupal.org/user/143 |
* making ready for release by Simon Lindsay - http://drupal.org/user/143 |
| 11 |
|
* Additional cleanup by Jeremy Andrews, http://drupal.org/user/409 |
| 12 |
*/ |
*/ |
| 13 |
|
|
| 14 |
include_once('xapian.php'); |
include_once('xapian.php'); |
| 15 |
|
|
| 16 |
|
define('XAPIAN_MINIMUM_BINDINGS', '1.0.2'); |
| 17 |
|
|
| 18 |
define('XAPIAN_WRITABLE', TRUE); |
define('XAPIAN_WRITABLE', TRUE); |
| 19 |
define('XAPIAN_FLUSH', TRUE); |
define('XAPIAN_FLUSH', TRUE); |
| 20 |
|
|
| 21 |
|
define('XAPIAN_LOCAL', 0); |
| 22 |
|
define('XAPIAN_REMOTE', 1); |
| 23 |
|
|
| 24 |
/** |
/** |
| 25 |
* Provide default error handler for xapian |
* Provide default error handler for xapian |
| 26 |
* |
* |
| 66 |
*/ |
*/ |
| 67 |
function xapian_requirements($phase) { |
function xapian_requirements($phase) { |
| 68 |
if (xapian_available()) { |
if (xapian_available()) { |
|
$severity = REQUIREMENT_OK; |
|
| 69 |
// Get Xapian bindings version, supporting PHP4 and PHP5 methods |
// Get Xapian bindings version, supporting PHP4 and PHP5 methods |
| 70 |
$version = (function_exists('xapian_version_string')) ? xapian_version_string() : Xapian::version_string(); |
$version = (function_exists('xapian_version_string')) ? xapian_version_string() : Xapian::version_string(); |
| 71 |
|
if (version_compare($version, XAPIAN_MINIMUM_BINDINGS) < 0) { |
| 72 |
|
$severity = REQUIREMENT_ERROR; |
| 73 |
|
$version = t('Your Xapian bindings are too old (%version). You must install at least version %minimum.', array('%version' => $version, '%minimum' => XAPIAN_MINIMUM_BINDINGS)); |
| 74 |
|
} |
| 75 |
|
else { |
| 76 |
|
$severity = REQUIREMENT_OK; |
| 77 |
|
} |
| 78 |
} |
} |
| 79 |
else { |
else { |
| 80 |
$severity = REQUIREMENT_ERROR; |
$severity = REQUIREMENT_ERROR; |
| 134 |
$form = array(); |
$form = array(); |
| 135 |
$form['#cache'] = FALSE; |
$form['#cache'] = FALSE; |
| 136 |
|
|
| 137 |
$database_type = variable_get('xapian_database_type', 0); |
$database_type = variable_get('xapian_database_type', XAPIAN_LOCAL); |
| 138 |
|
|
| 139 |
// Create a database fieldset |
// Create a database fieldset |
| 140 |
$form['database'] = array( |
$form['database'] = array( |
| 146 |
$form['database']['xapian_database_type'] = array( |
$form['database']['xapian_database_type'] = array( |
| 147 |
'#type' => 'radios', |
'#type' => 'radios', |
| 148 |
'#title' => t('Type'), |
'#title' => t('Type'), |
| 149 |
'#default_value' => $database_type, |
'#default_value' => $database_type ? $database_type : XAPIAN_LOCAL, |
| 150 |
'#options' => array(t('Local'), t('Remote')), |
'#options' => array( |
| 151 |
|
XAPIAN_LOCAL => t('Local'), |
| 152 |
|
XAPIAN_REMOTE => t('Remote')), |
| 153 |
); |
); |
| 154 |
|
|
| 155 |
// local database settings |
// local database settings |
| 157 |
'#type' => 'fieldset', |
'#type' => 'fieldset', |
| 158 |
'#title' => t('Local database options'), |
'#title' => t('Local database options'), |
| 159 |
'#collapsible' => TRUE, |
'#collapsible' => TRUE, |
| 160 |
'#collapsed' => ($database_type != 0) |
'#collapsed' => ($database_type != XAPIAN_LOCAL) |
| 161 |
); |
); |
| 162 |
$form['database']['local_database']['xapian_database_path'] = array( |
$form['database']['local_database']['xapian_database_path'] = array( |
| 163 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 164 |
'#title' => t('Path to Xapian database'), |
'#title' => t('Path to Xapian database'), |
| 165 |
'#default_value' => variable_get('xapian_database_path', file_directory_path() .'/xapian_database'), |
'#default_value' => variable_get('xapian_database_path', file_directory_path() .'/xapian_database'), |
| 166 |
'#required' => ($database_type == 0), |
'#required' => ($database_type == XAPIAN_LOCAL), |
| 167 |
'#description' => t('Directory where your local Xapian database will be created. Specify a directory writable by your web server process.'), |
'#description' => t('Directory where your local Xapian database will be created. Specify a directory writable by your web server process.'), |
| 168 |
); |
); |
| 169 |
|
|
| 172 |
'#type' => 'fieldset', |
'#type' => 'fieldset', |
| 173 |
'#title' => t('Remote database options'), |
'#title' => t('Remote database options'), |
| 174 |
'#collapsible' => TRUE, |
'#collapsible' => TRUE, |
| 175 |
'#collapsed' => ($database_type != 1), |
'#collapsed' => ($database_type != XAPIAN_REMOTE), |
| 176 |
); |
); |
| 177 |
$form['database']['remote_database']['xapian_database_hostname'] = array( |
$form['database']['remote_database']['xapian_database_hostname'] = array( |
| 178 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 179 |
'#title' => t('Database server'), |
'#title' => t('Database server'), |
| 180 |
'#default_value' => variable_get('xapian_database_hostname', ''), |
'#default_value' => variable_get('xapian_database_hostname', ''), |
| 181 |
'#required' => ($database_type == 1), |
'#required' => ($database_type == XAPIAN_REMOTE), |
| 182 |
'#description' => t('IP address or host name of remote server running xapian-tcpsrv.'), |
'#description' => t('IP address or host name of remote server running xapian-tcpsrv.'), |
| 183 |
); |
); |
| 184 |
$form['database']['remote_database']['xapian_database_port'] = array( |
$form['database']['remote_database']['xapian_database_port'] = array( |
| 185 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 186 |
'#title' => t('Database port'), |
'#title' => t('Database port'), |
| 187 |
'#default_value' => variable_get('xapian_database_port', '6431'), |
'#default_value' => variable_get('xapian_database_port', '6431'), |
| 188 |
'#required' => ($database_type == 1), |
'#required' => ($database_type == XAPIAN_REMOTE), |
| 189 |
'#validate' => array('_xapian_validate_port' => array('xapian_database_port')), |
'#validate' => array('_xapian_validate_port' => array('xapian_database_port')), |
| 190 |
'#description' => t('Remote port that xapian-tcpsrv is listening on.'), |
'#description' => t('Remote port that xapian-tcpsrv is listening on.'), |
| 191 |
); |
); |
| 192 |
|
|
| 193 |
|
// Optional write-only database (see http://drupal.org/node/282855) |
| 194 |
|
$form['database']['writeonly'] = array( |
| 195 |
|
'#type' => 'fieldset', |
| 196 |
|
'#title' => t('Optional write-only database settings'), |
| 197 |
|
'#collapsible' => TRUE, |
| 198 |
|
'#collapsed' => variable_get('xapian_write_database_hostname', '') && variable_get('xapian_write_database_port', '') ? FALSE : TRUE, |
| 199 |
|
'#description' => t('Leave these optional settings blank to use the above settings for both read and write database access. If you would like to send write queries to a different database than read queries, configure the remote write-only database settings below. Using a separate remote write-only server allows you to efficiently scale your search solution across multiple web servers, and avoids potential issues with lock contention.'), |
| 200 |
|
); |
| 201 |
|
|
| 202 |
|
$form['database']['writeonly']['xapian_write_database_hostname'] = array( |
| 203 |
|
'#type' => 'textfield', |
| 204 |
|
'#title' => t('Write-only database server'), |
| 205 |
|
'#default_value' => variable_get('xapian_write_database_hostname', ''), |
| 206 |
|
'#description' => t('IP address or host name of remote server running %writable.', array('%writable' => t('xapian-tcpsrv --writable'))), |
| 207 |
|
); |
| 208 |
|
$form['database']['writeonly']['xapian_write_database_port'] = array( |
| 209 |
|
'#type' => 'textfield', |
| 210 |
|
'#title' => t('Write-only database port'), |
| 211 |
|
'#default_value' => variable_get('xapian_write_database_port', ''), |
| 212 |
|
'#validate' => array('_xapian_validate_port' => array('xapian_write_database_port')), |
| 213 |
|
'#description' => t('Remote port that %writable is listening on.', array('%writable' => t('xapian-tcpsrv --writable'))), |
| 214 |
|
); |
| 215 |
|
|
| 216 |
// indexing settings |
// indexing settings |
| 217 |
$form['performance'] = array( |
$form['performance'] = array( |
| 218 |
'#type' => 'fieldset', |
'#type' => 'fieldset', |
| 372 |
* @return object |
* @return object |
| 373 |
*/ |
*/ |
| 374 |
function _xapian_init_database($writable = FALSE, $flush = FALSE) { |
function _xapian_init_database($writable = FALSE, $flush = FALSE) { |
| 375 |
static $database; |
static $database = NULL; |
| 376 |
static $writable_database; |
static $writable_database = NULL; |
| 377 |
|
|
| 378 |
if ($flush) { |
if ($flush) { |
| 379 |
if (is_object($writable_database)) { |
if (is_object($writable_database)) { |
| 393 |
} |
} |
| 394 |
|
|
| 395 |
try { |
try { |
| 396 |
$database_type = variable_get('xapian_database_type', 0); |
$database_type = variable_get('xapian_database_type', XAPIAN_LOCAL); |
| 397 |
|
|
| 398 |
if ($database_type == 0) { // Local database |
if ($database_type == XAPIAN_LOCAL) { // Local database |
| 399 |
$database_path = variable_get('xapian_database_path', NULL); |
$database_path = variable_get('xapian_database_path', NULL); |
| 400 |
|
|
| 401 |
if (empty($database_path)) { |
if (empty($database_path)) { |
| 405 |
|
|
| 406 |
$db_source = $database_path; |
$db_source = $database_path; |
| 407 |
} |
} |
| 408 |
elseif ($database_type == 1) { |
elseif ($database_type == XAPIAN_REMOTE) { |
| 409 |
$database_host = variable_get('xapian_database_hostname', ''); |
$database_host = variable_get('xapian_database_hostname', ''); |
| 410 |
$database_port = variable_get('xapian_database_port', 6431); |
$database_port = variable_get('xapian_database_port', 6431); |
| 411 |
|
|
| 427 |
} |
} |
| 428 |
} |
} |
| 429 |
catch (Exception $e) { |
catch (Exception $e) { |
| 430 |
watchdog('xapian', $e->getMessage()); |
watchdog('xapian', $e->getMessage() . ", writable($writable) flush($flush) type($database_type)"); |
| 431 |
return NULL; |
return NULL; |
| 432 |
} |
} |
| 433 |
} |
} |
| 593 |
static $stemmer; |
static $stemmer; |
| 594 |
static $indexer; |
static $indexer; |
| 595 |
|
|
|
$db = _xapian_init_database(XAPIAN_WRITABLE); |
|
|
if (!is_object($db)) { |
|
|
watchdog('xapian', 'Could not get writable database.'); |
|
|
return FALSE; |
|
|
} |
|
|
|
|
| 596 |
// Track which content is being indexed until the Xapian cache is flushed. |
// Track which content is being indexed until the Xapian cache is flushed. |
| 597 |
// If we fail to flush the cache to disk for any reason, we will re-attempt |
// If we fail to flush the cache to disk for any reason, we will re-attempt |
| 598 |
// to index this content. See bug #272140 for full details. |
// to index this content. See bug #272140 for full details. |
| 599 |
db_query('UPDATE {xapian_index_queue} SET status = status + 1 WHERE nid = %d', $node->nid); |
db_query('UPDATE {xapian_index_queue} SET status = status + 1, indexed = %d WHERE nid = %d', time(), $node->nid); |
| 600 |
|
|
| 601 |
// Provide mechanism to override default indexing behaviour |
// Provide mechanism to override default indexing behaviour |
| 602 |
$function = $node->type .'_xapian_index'; |
$function = $node->type .'_xapian_index'; |
| 606 |
$function = 'node_xapian_index'; |
$function = 'node_xapian_index'; |
| 607 |
} |
} |
| 608 |
|
|
| 609 |
|
// If not published, remove node from index |
| 610 |
|
if ($node->status != 1) { |
| 611 |
|
xapian_remove_node_from_index($node); |
| 612 |
|
return TRUE; |
| 613 |
|
} |
| 614 |
|
|
| 615 |
|
$db = _xapian_init_database(XAPIAN_WRITABLE); |
| 616 |
|
if (!is_object($db)) { |
| 617 |
|
watchdog('xapian', t('Could not get writable database.')); |
| 618 |
|
return FALSE; |
| 619 |
|
} |
| 620 |
|
|
| 621 |
$terms = $function($node); |
$terms = $function($node); |
| 622 |
if (is_array($terms)) { |
if (is_array($terms)) { |
| 623 |
|
|
| 793 |
if ($not_flushed > 1) { |
if ($not_flushed > 1) { |
| 794 |
// Re-index content that wasn't flushed to disk last time, minus the node |
// Re-index content that wasn't flushed to disk last time, minus the node |
| 795 |
// which failed last time. |
// which failed last time. |
| 796 |
$sql = 'SELECT nid FROM {xapian_index_queue} WHERE status > 0 ORDER BY COALESCE(priority, 0) DESC, added ASC'; |
$sql = 'SELECT nid FROM {xapian_index_queue} WHERE status > 0 ORDER BY indexed ASC'; |
| 797 |
$config = variable_get('xapian_indexing_throttle', 100); |
$config = variable_get('xapian_indexing_throttle', 100); |
| 798 |
$error = $not_flushed - 1; |
$error = $not_flushed - 1; |
| 799 |
$limit = $config > $error ? $error : $config; |
$limit = $config > $error ? $error : $config; |