diff -urN apachesolr.orig/apachesolr.admin.inc apachesolr/apachesolr.admin.inc
--- apachesolr.orig/apachesolr.admin.inc 2009-12-27 18:29:34.000000000 +0100
+++ apachesolr/apachesolr.admin.inc 2010-02-07 14:38:13.000000000 +0100
@@ -22,27 +22,6 @@
}
}
- $form['apachesolr_host'] = array(
- '#type' => 'textfield',
- '#title' => t('Solr host name'),
- '#default_value' => variable_get('apachesolr_host', 'localhost'),
- '#description' => t('Host name of your Solr server, e.g. localhost or example.com.'),
- '#required' => TRUE,
- );
- $form['apachesolr_port'] = array(
- '#type' => 'textfield',
- '#title' => t('Solr port'),
- '#default_value' => variable_get('apachesolr_port', '8983'),
- '#description' => t('Port on which the Solr server listens. The Jetty example server is 8983, while Tomcat is 8080 by default.'),
- '#required' => TRUE,
- );
- $form['apachesolr_path'] = array(
- '#type' => 'textfield',
- '#title' => t('Solr path'),
- '#default_value' => variable_get('apachesolr_path', '/solr'),
- '#description' => t('Path that identifies the Solr request handler to be used.'),
- );
-
$numbers = drupal_map_assoc(array(1, 5, 10, 20, 50, 100, 200));
$form['apachesolr_cron_limit'] = array(
'#type' => 'select',
@@ -118,6 +97,239 @@
}
/**
+ * Callback for configuring Solr servers.
+ */
+function apachesolr_settings_servers($server_id = NULL, $delete = NULL) {
+ $output = '';
+ $servers = variable_get('apachesolr_servers', array());
+ if ($delete == 'delete' && isset($servers[$server_id])) {
+ return drupal_get_form('apachesolr_settings_servers_delete', $server_id);
+ }
+ $server_id = is_null($server_id) ? 'add' : $server_id;
+ if (count($servers)) {
+ $header = array('#', t('Server name'), t('Host name'), t('Port'), t('Path'), t('Query server'), t('Index server'), t('Status'), array('data' => t('Operations'), 'colspan' => 2));
+ $rows = array();
+ foreach ($servers as $delta => $server) {
+ $ping = FALSE;
+ try {
+ $solr = apachesolr_get_server($server['host'], $server['port'], $server['path']);
+ $ping = @$solr->ping(variable_get('apachesolr_ping_timeout', 4));
+ // If there is no $solr object, there is no server available, so don't continue.
+ if (!$ping) {
+ throw new Exception(t('No Solr instance available for !host:!port/!path', array('!host' => $server['host'], '!port' => $server['port'], '!path' => ltrim($server['path'], '/'))));
+ }
+ }
+ catch (Exception $e) {
+ watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
+ }
+
+ $row = array($delta, $server['name'], $server['host'], $server['port'], $server['path'], $server['query'] ? t('Yes') : t('No'), $server['index'] ? t('Yes') : t('No'), $ping ? t('Successfully contacted') : t('Cannot be contacted!'), l(t('modify'), 'admin/settings/apachesolr/servers/'. $delta), l(t('delete'), 'admin/settings/apachesolr/servers/'. $delta .'/delete'));
+ if ($server_id == (string)$delta) {
+ $rows[] = array(
+ 'data' => $row,
+ 'class' => 'apachesolr-servers-active-server',
+ );
+ }
+ else {
+ $rows[] = $row;
+ }
+ }
+ $element = array(
+ '#type' => 'fieldset',
+ '#title' => t('Solr servers currentlly configured on this site'),
+ '#collapsible' => TRUE,
+ '#collpased' => FALSE,
+ '#value' => theme('table', $header, $rows) . ($server_id != 'add' ? '
'. l(t('Add a new server'), 'admin/settings/apachesolr/servers') .'
' : ''),
+ );
+ $output .= theme('fieldset', $element);
+ drupal_add_css(drupal_get_path('module', 'apachesolr') .'/apachesolr.css');
+ }
+ else {
+ $output .= t('There are no Solr servers configured yet. Use the form bellow to enter a Solr server.');
+ }
+ return $output . drupal_get_form('apachesolr_settings_servers_form', $server_id);
+}
+
+/**
+ * Solr servers form definition.
+ */
+function apachesolr_settings_servers_form(&$form_state, $server_id) {
+ $servers = variable_get('apachesolr_servers', array());
+ $server = $server_id == 'add' ? array('name' => '', 'host' => 'localhost', 'port' => '8983', 'path' => '/solr', 'query' => TRUE, 'index' => FALSE) : $servers[$server_id];
+ $form = array();
+ $form['server_id'] = array(
+ '#type' => 'value',
+ '#value' => $server_id,
+ );
+ $form['container'] = array(
+ '#type' => 'fieldset',
+ '#title' => $server_id == 'add' ? t('Add a new Solr server') : t('Configuration for server #%no: %name', array('%no' => $server_id, '%name' => $server['name'])),
+ '#collapsible' => TRUE,
+ '#collpased' => FALSE,
+ );
+ $form['container']['name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Server name'),
+ '#description' => t('Enter a maximum 50 characters internal name for this server. It will be use only for administrative reasons, to help dealing with more than one server.'),
+ '#default_value' => $server['name'],
+ '#required' => TRUE,
+ '#maxlength' => 50,
+ );
+ $form['container']['url'] = array(
+ '#tree' => TRUE,
+ );
+ $form['container']['url']['host'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Solr host name'),
+ '#description' => t('Host name of your Solr server, e.g. localhost or example.com.'),
+ '#default_value' => $server['host'],
+ '#required' => TRUE,
+ );
+ $form['container']['url']['port'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Solr port'),
+ '#description' => t('Port on which the Solr server listens. The Jetty example server is 8983, while Tomcat is 8080 by default.'),
+ '#default_value' => $server['port'],
+ '#required' => TRUE,
+ );
+ $form['container']['url']['path'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Solr path'),
+ '#description' => t('Path that identifies the Solr request handler to be used.'),
+ '#default_value' => $server['path'],
+ );
+ $form['container']['query'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('This server is used for queries'),
+ '#description' => t('Check this box in order to have this server acting as query server.'),
+ '#default_value' => $server['query'],
+ );
+ $form['container']['index'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('This server used for indexing'),
+ '#description' => t('Check this box if you want too use this server as index server. Note that you cannot configure more than one index server.'),
+ '#default_value' => $server['index'],
+ );
+ $form['container']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => is_numeric($server_id) ? t('Save') : t('Add'),
+ );
+ return $form;
+}
+
+/**
+ * Solr servers form validation callback handler.
+ */
+function apachesolr_settings_servers_form_validate($form, &$form_state) {
+ // Check for existing servers other than current.
+ foreach (variable_get('apachesolr_servers', array()) as $delta => $server) {
+ if (($form_state['values']['server_id'] == 'add') || ($form_state['values']['server_id'] != 'add' && $form_state['values']['server_id'] != $delta)) {
+
+ // Does other server have this name?
+ if ($form_state['values']['name'] == $server['name']) {
+ form_set_error('name', t('A server with the name @name is already defined in row #@row.', array('@name' => $server['name'], '@row' => $delta)));
+ }
+
+ // Does other server have this URL?
+ if ($form_state['values']['url']['host'] == $server['host'] && $form_state['values']['url']['port'] == $server['port'] && $form_state['values']['url']['path'] == $server['path']) {
+ form_set_error('url', t('A server with the URL !host:!port/!path is already defined in row #@row.', array('!host' => $server['host'], '!port' => $server['port'], '!path' => ltrim($server['path'], '/'), '@row' => $delta)));
+ }
+ }
+ }
+}
+
+/**
+ * Solr servers form submit callback handler.
+ */
+function apachesolr_settings_servers_form_submit($form, &$form_state) {
+ $servers = variable_get('apachesolr_servers', array());
+ $server = array(
+ 'name' => $form_state['values']['name'],
+ 'host' => $form_state['values']['url']['host'],
+ 'port' => $form_state['values']['url']['port'],
+ 'path' => $form_state['values']['url']['path'],
+ 'query' => $form_state['values']['query'],
+ 'index' => $form_state['values']['index'],
+ );
+
+ // If this is an index server, remove the index attribute from the others.
+ if ($server['index']) {
+ foreach ($servers as $delta => $server_item) {
+ $servers[$delta]['index'] = FALSE;
+ }
+ }
+
+ if ($form_state['values']['server_id'] == 'add') {
+ $servers[] = $server;
+ }
+ else {
+ $servers[$form_state['values']['server_id']] = $server;
+ }
+
+ // Save servers into one single variable.
+ variable_set('apachesolr_servers', $servers);
+
+ drupal_set_message(t('Server !host:!port/!path was saved as %name', array('!host' => $server['host'], '!port' => $server['port'], '!path' => ltrim($server['path'], '/'), '%name' => $server['name'])));
+ $form_state['redirect'] = 'admin/settings/apachesolr/servers';
+}
+
+/**
+ * Solr server deleting confirmation page
+ */
+function apachesolr_settings_servers_delete(&$form_state, $server_id) {
+ $servers = variable_get('apachesolr_servers', array());
+ $server = $servers[$server_id];
+
+ $form['#redirect'] = 'admin/settings/apachesolr/servers';
+ $form['server_id'] = array(
+ '#type' => 'value',
+ '#value' => $server_id,
+ );
+
+ $question = t('Are you sure you want to delete the Solr server %name?', array('%name' => $server['name']));
+
+ $items = array(
+ t('Name: @name', array('@name' => $server['name'])),
+ t('Host: @host', array('@host' => $server['host'])),
+ t('Port: @port', array('@port' => $server['port'])),
+ t('Path: @path', array('@path' => $server['path'])),
+ t('Query server: @query', array('@query' => $server['query'] ? t('Yes') : t('No'))),
+ t('Index server: @index', array('@index' => $server['index'] ? t('Yes') : t('No'))),
+ );
+ $description = theme('item_list', $items, t('Solr server details:'));
+
+ // Check if this is the only query server.
+ $query = 0;
+ foreach ($servers as $delta => $server_item) {
+ if ($delta != $server_id && $server_item['query']) {
+ $query++;
+ }
+ }
+
+ $items = array();
+ if ($server['index']) {
+ $items[] = t('This Solr server is the server used to index this site. If you will delete it than you\'ll have to configure other server as index server.');
+ }
+ if ($query == 0) {
+ $items[] = t('This Solr server is the only one configured to be queried for data. If you will delete it than you\'ll have to configure at least other server as query server.');
+ }
+ $items[] = t('This action cannot be undone.');
+ $description .= theme('item_list', $items, t('Warnings:'));
+
+ return confirm_form($form, $question, 'admin/settings/apachesolr/servers', $description, t('Delete'), t('Cancel'));
+}
+
+/**
+ * Solr server delete callback handler.
+ */
+function apachesolr_settings_servers_delete_submit($form, &$form_state) {
+ $servers = variable_get('apachesolr_servers', array());
+ $server = array_splice($servers, $form_state['values']['server_id'], 1);
+ drupal_set_message(t('The Solr server %name (!host:!port/!path) has been deleted.', array('%name' => $server[0]['name'], '!host' => $server[0]['host'], '!port' => $server[0]['port'], '!path' => ltrim($server[0]['path'], '/'))));
+ variable_set('apachesolr_servers', $servers);
+}
+
+/**
* Gets information about the fields already in solr index.
*/
function apachesolr_index_page() {
diff -urN apachesolr.orig/apachesolr.install apachesolr/apachesolr.install
--- apachesolr.orig/apachesolr.install 2009-12-27 18:15:50.000000000 +0100
+++ apachesolr/apachesolr.install 2010-02-07 14:38:13.000000000 +0100
@@ -15,26 +15,51 @@
// Ensure translations don't break at install time
$t = get_t();
if ($phase == 'runtime' && $file_exists) {
- $host = variable_get('apachesolr_host', 'localhost');
- $port = variable_get('apachesolr_port', 8983);
- $path = variable_get('apachesolr_path', '/solr');
- $ping = FALSE;
- try {
- $solr = apachesolr_get_solr();
- $ping = @$solr->ping(variable_get('apachesolr_ping_timeout', 4));
- // If there is no $solr object, there is no server available, so don't continue.
- if (!$ping) {
- throw new Exception(t('No Solr instance available when checking requirements.'));
- }
- }
- catch (Exception $e) {
- watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
- }
- $value = $ping ? $t('Your site has contacted the Apache Solr server.') : $t('Your site was unable to contact the Apache Solr server.');
- $severity = $ping ? REQUIREMENT_OK : REQUIREMENT_ERROR;
- $description = theme('item_list', array($t('Host: %host', array('%host' => $host)),
- $t('Port: %port', array('%port' => $port)),
- $t('Path: %path', array('%path' => $path))));
+ $servers = variable_get('apachesolr_servers', array());
+ $contacted = 0;
+ $items = array();
+ foreach ($servers as $delta => $server) {
+ $ping = FALSE;
+ try {
+ $solr = apachesolr_get_server($server['host'], $server['port'], $server['path']);
+ $ping = @$solr->ping(variable_get('apachesolr_ping_timeout', 4));
+ // If there is no $solr object, there is no server available, so don't continue.
+ if ($ping) {
+ $contacted++;
+ }
+ else {
+ throw new Exception(t('No Solr instance available when checking requirements.'));
+ }
+ }
+ catch (Exception $e) {
+ watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
+ }
+ $roles = array();
+ if ($server['query']) {
+ $roles[] = $t('query server');
+ }
+ if ($server['index']) {
+ $roles[] = $t('index server');
+ }
+ $roles = count($roles) ? implode(', ', $roles) : $t('No role assigned');
+ $items[] = $t('URL: !host:!port/!path; Roles: @roles; Status: @contacted', array('!host' => $server['host'], '!port' => $server['port'], '!path' => ltrim($server['path'], '/'), '@roles' => $roles, '@contacted' => $ping ? $t('successfully contacted') : $t('cannot be contacted!')));
+ }
+ if (count($servers)) {
+ $value = $t('@count Solr servers are configured on your site.', array('@count' => count($servers))) .' ';
+ if ($contacted) {
+ $value .= ($contacted == 1) ? $t('One has been successfully contacted.') : $t('@contacted of them were successfully contacted.', array('@contacted' => $contacted));
+ $severity = REQUIREMENT_OK;
+ }
+ else {
+ $value .= $t('None were successfully contacted.');
+ $severity = REQUIREMENT_ERROR;
+ }
+ }
+ else {
+ $value = $t('Your site has no Solr server configured yet. You can add Solr servers here.', array('!url' => url('admin/settings/apachesolr/servers')));
+ $severity = REQUIREMENT_ERROR;
+ }
+ $description = count($servers) ? theme('item_list', $items) : '';
$requirements['apachesolr'] = array(
'title' => $t('Apache Solr'),
'value' => $value,
@@ -261,3 +286,28 @@
db_create_table($ret, 'cache_apachesolr', $table);
return $ret;
}
+
+/**
+ * Copy the old Solr connection infos to the new array variable.
+ */
+function apachesolr_update_6006() {
+ $ret = array();
+ $server = array(
+ 'name' => 'Solr server',
+ 'host' => variable_get('apachesolr_host', 'localhost'),
+ 'port' => variable_get('apachesolr_port', '8983'),
+ 'path' => variable_get('apachesolr_path', '/solr'),
+ 'query' => TRUE,
+ 'index' => TRUE,
+ );
+ variable_set('apachesolr_servers', array($server));
+ $ret[] = array('success' => TRUE, 'query' => 'Solr data is transfered to the new format:'. print_r(array($server), TRUE) .'
');
+
+ // @todo: Delete old variables
+ // variable_del('apachesolr_host');
+ // variable_del('apachesolr_port');
+ // variable_del('apachesolr_path');
+ // $ret[] = array('success' => TRUE, 'query' => 'Drupal variables: "apachesolr_host", "apachesolr_port", "apachesolr_path" were deleted.');
+
+ return $ret;
+}
diff -urN apachesolr.orig/apachesolr.module apachesolr/apachesolr.module
--- apachesolr.orig/apachesolr.module 2010-01-02 15:42:58.000000000 +0100
+++ apachesolr/apachesolr.module 2010-02-07 15:29:17.000000000 +0100
@@ -30,6 +30,30 @@
'file' => 'apachesolr.admin.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
+ $items['admin/settings/apachesolr/servers'] = array(
+ 'title' => 'Solr Servers',
+ 'page callback' => 'apachesolr_settings_servers',
+ 'weight' => -9,
+ 'access arguments' => array('administer search'),
+ 'file' => 'apachesolr.admin.inc',
+ 'type' => MENU_LOCAL_TASK,
+ );
+ $items['admin/settings/apachesolr/servers/%apachesolr_server'] = array(
+ 'title' => 'Solr Servers',
+ 'page callback' => 'apachesolr_settings_servers',
+ 'page arguments' => array(4),
+ 'access arguments' => array('administer search'),
+ 'file' => 'apachesolr.admin.inc',
+ 'type' => MENU_CALLBACK,
+ );
+ $items['admin/settings/apachesolr/servers/%apachesolr_server/delete'] = array(
+ 'title' => 'Solr Servers',
+ 'page callback' => 'apachesolr_settings_servers',
+ 'page arguments' => array(4, 'delete'),
+ 'access arguments' => array('administer search'),
+ 'file' => 'apachesolr.admin.inc',
+ 'type' => MENU_CALLBACK,
+ );
$items['admin/settings/apachesolr/enabled-filters'] = array(
'title' => 'Enabled filters',
'page callback' => 'drupal_get_form',
@@ -100,6 +124,20 @@
}
/**
+ * Menu loader for %apachesolr_server.
+ *
+ * @param $server_id
+ * Argument passed.
+ *
+ * @return
+ * The server informations ID of FALSE.
+ */
+function apachesolr_server_load($server_id = NULL) {
+ $servers = variable_get('apachesolr_servers', array());
+ return isset($servers[$server_id]) ? $servers[$server_id] : FALSE;
+}
+
+/**
* Determines Apache Solr's behavior when searching causes an exception (e.g. Solr isn't available.)
* Depending on the admin settings, possibly redirect to Drupal's core search.
*
@@ -1312,24 +1350,116 @@
}
/**
- * Factory method for solr singleton object. Structure allows for an arbitrary
- * number of solr objects to be used based on the host, port, path combination.
- * Get an instance like this:
- * $solr = apachesolr_get_solr();
- */
-function apachesolr_get_solr($host = NULL, $port = NULL, $path = NULL) {
- static $solr_cache;
-
- if (empty($host)) {
- $host = variable_get('apachesolr_host', 'localhost');
+ * Internal method to get a solr server instance. This is exported to its own
+ * function so we could check servers availability through cron.
+ *
+ * This method does heavy ping() usage which implies numerous and useless
+ * HTTP request in most cases. That's why this method should be externalized.
+ *
+ * TODO: note that using this implementation, the Balancer override is almost
+ * useless, this could be improved.
+ */
+function _apachesolr_get_solr($readonly = TRUE) {
+ static $loadbalancer;
+
+ // Load includes and instanciate balancer if we need it.
+ if (!isset($loadbalancer)) {
+ include_once(drupal_get_path('module', 'apachesolr') . '/Drupal_Apache_Solr_Service_Balancer.php');
+ try {
+ $loadbalancer = new Drupal_Apache_Solr_Service_Balancer();
+ }
+ catch (Exception $e) {
+ watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
+ return;
+ }
}
- if (empty($port)) {
- $port = variable_get('apachesolr_port', '8983');
+
+ // Get available servers (event if in case we are going through
+ // apachesolr_get_solr() this variable already been loaded this won't hurt
+ // because all variables are statically cached.
+ $servers = variable_get('apachesolr_servers', array());
+
+ // Go through services to load them all (matching to the $readonly
+ // parameter).
+ foreach ($servers as $delta => $server) {
+ try {
+ if ($readonly && $server['query']) {
+ $loadbalancer->addReadService(apachesolr_get_server($server['host'], $server['port'], $server['path']));
+ }
+ else if (!$readonly && $server['index']) {
+ $loadbalancer->addReadService(apachesolr_get_server($server['host'], $server['port'], $server['path']));
+ }
+ }
+ catch (Exception $e) {
+ watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
+ return;
+ }
}
- if (empty($path)) {
- $path = variable_get('apachesolr_path', '/solr');
+
+ // Selected reader and writers are cached within the load balancer class.
+ return $readonly ? $loadbalancer->getReadService() : $loadbalancer->getWriteService();
+}
+
+/**
+ * Method used to obtain the Solr load balancer object
+ */
+function apachesolr_get_solr($readonly = TRUE) {
+ static $reader, $writer;
+
+ if (($readonly && !isset($reader)) || (!$readonly && !isset($writer)) ) {
+
+ // Get available servers
+ $servers = variable_get('apachesolr_servers', array());
+
+ // We use only one Solr server (this may be the main usage of this module)
+ // Do not load the entire Balancer API use only a single Solr object.
+ if (count($servers) == 1) {
+ $writer = apachesolr_get_server($servers[0]['host'], $servers[0]['port'], $servers[0]['path']);
+ $reader = $writer;
+ }
+
+ // Asked for a reader, hope then the PHP runtime won't ask for a writer
+ // unfortunately this is difficult to predict.
+ else if ($readonly && $delta = variable_get('apachesolr_current_reader', FALSE)) {
+ $server = &$servers[$delta];
+ $reader = apachesolr_get_server($server['host'], $server['port'], $server['path']);
+ }
+
+ // Asked for a writer.
+ else if (!$readonly && $delta = variable_get('apachesolr_current_writer', FALSE)) {
+ $server = &$servers[$delta];
+ $writer = apachesolr_get_server($server['host'], $server['port'], $server['path']);
+ // In case we set the writer, set also the reader on the same instance
+ // to ensure we are going to modify and read on the same instance.
+ // TODO: this might be wrong, correct me if it is.
+ $reader = $writer;
+ }
+
+ // None variable set, we are going to run the load balancer implementation
+ // to find one available server. Note that this will do a lot of HTTP SolR
+ // ping requests so it can be quite heavy.
+ else {
+ if ($readonly) {
+ $reader = _apachesolr_get_solr($readonly);
+ }
+ else {
+ // We won't load writer and reader together, because in most cases
+ // clients will hit to do search requests, only cron (in most cases)
+ // will ask for a writer.
+ $writer = _apachesolr_get_solr($readonly);
+ }
+ }
}
+ return $readonly ? $reader : $writer;
+}
+
+/**
+ * Method used to obtain a single Solr object. A clone of old apachesolr_get_solr() function but arguments are mandatory.
+ */
+function apachesolr_get_server($host, $port, $path) {
+ static $solr_cache;
+
if (empty($solr_cache[$host][$port][$path])) {
list($module, $filepath, $class) = variable_get('apachesolr_service_class', array('apachesolr', 'Drupal_Apache_Solr_Service.php', 'Drupal_Apache_Solr_Service'));
include_once(drupal_get_path('module', $module) .'/'. $filepath);
diff -urN apachesolr.orig/Drupal_Apache_Solr_Service.php apachesolr/Drupal_Apache_Solr_Service.php
--- apachesolr.orig/Drupal_Apache_Solr_Service.php 2009-12-26 18:12:12.000000000 +0100
+++ apachesolr/Drupal_Apache_Solr_Service.php 2010-02-07 14:49:08.000000000 +0100
@@ -33,7 +33,8 @@
* @return
* (float) seconds taken to ping the server, FALSE if timeout occurs.
*/
- public function ping($timeout = 2) {
+ public function ping() {
+ $timeout = func_get_arg(0);
$start = microtime(TRUE);
if ($timeout <= 0.0) {