diff --git a/.travis.yml b/.travis.yml
index 3a44cd74..102d01c8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,6 @@ php:
- 7.0
- 5.6
- 5.5
-- 5.4
services:
- redis
- docker
diff --git a/composer.json b/composer.json
index 7b323ef3..9659031e 100644
--- a/composer.json
+++ b/composer.json
@@ -18,17 +18,17 @@
}
],
"require": {
- "php" : ">=5.4",
+ "php" : ">=5.5",
"semsol/arc2": "v2.2.4",
"chrisboulton/php-resque": "dev-master#98fde571db008a8b48e73022599d1d1c07d4a7b5",
"monolog/monolog" : "~1.13",
"mongodb/mongodb": "1.0.4"
},
"require-dev": {
- "phpunit/phpunit": "4.1.*",
+ "phpunit/phpunit": "4.8.",
"squizlabs/php_codesniffer": "3.2.*"
- },
+ },
"autoload": {
"classmap": ["src/"]
- }
+ }
}
diff --git a/docker-compose.yml b/docker-compose.yml
index 3cf8dd7f..95fae1a8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,4 +1,4 @@
mongo:
- image: mongo/2.6.12:latest
+ image: rossfsinger/mongo-2.6.12:latest
ports:
- "27017:27017"
\ No newline at end of file
diff --git a/src/mongo/Config.class.php b/src/mongo/Config.class.php
index 62ecd5c7..7108981f 100644
--- a/src/mongo/Config.class.php
+++ b/src/mongo/Config.class.php
@@ -38,61 +38,61 @@ class Config implements IConfigInstance
* The defined database indexes, keyed by database name
* @var array
*/
- private $indexes = array();
+ private $indexes = [];
/**
* @var array
*/
- private $cardinality = array();
+ private $cardinality = [];
/**
* The connection strings for each defined database
* @var array
*/
- private $dbConfig = array();
+ private $dbConfig = [];
/**
* All of the defined viewSpecs
* @var array
*/
- private $viewSpecs = array();
+ private $viewSpecs = [];
/**
* All of the defined tableSpecs
* @var array
*/
- private $tableSpecs = array();
+ private $tableSpecs = [];
/**
* All of the defined searchDocSpecs
* @var array
*/
- protected $searchDocSpecs = array();
+ protected $searchDocSpecs = [];
/**
* Defined database configuration: dbname, collections, etc.
* @var array
*/
- private $databases = array();
+ private $databases = [];
/**
* All defined namespaces
*
* @var array
*/
- protected $ns = array();
+ protected $ns = [];
/**
* The transaction log db config
* @var array
*/
- protected $tConfig = array();
+ protected $tConfig = [];
/**
* The value should be the name of a class that implement iTripodSearchProvider keyed by storename
* @var array
*/
- protected $searchProviderClassName = array();
+ protected $searchProviderClassName = [];
/**
* All of the predicates associated with a particular spec document
@@ -105,12 +105,12 @@ class Config implements IConfigInstance
* A simple map between collection names and the database name they belong to
* @var array
*/
- protected $collectionDatabases = array();
+ protected $collectionDatabases = [];
/**
* @var array
*/
- protected $activeMongoConnections = array();
+ protected $activeMongoConnections = [];
/**
* @var string
@@ -120,12 +120,12 @@ class Config implements IConfigInstance
/**
* @var array
*/
- protected $dataSources = array();
+ protected $dataSources = [];
/**
* @var array
*/
- protected $podConnections = array();
+ protected $podConnections = [];
const VALIDATE_MIN = 'MIN';
const VALIDATE_MAX = 'MAX';
@@ -140,17 +140,25 @@ class Config implements IConfigInstance
* Database connections, keyed by datasource, so we're not inadvertently opening many db connections through getDatabase()
* @var array
*/
- protected $connections = array();
+ protected $connections = [];
/**
* @var int
*/
protected $mongoCursorTimeout = 30000;
+ protected $batchSize = [
+ OP_TABLES => 100,
+ OP_SEARCH => 100,
+ OP_VIEWS => 25
+ ];
+
/**
* Config should not be instantiated directly: use Config::getInstance()
*/
- private function __construct() {}
+ private function __construct()
+ {
+ }
/**
* @return int
@@ -177,107 +185,84 @@ public function setMongoCursorTimeout($mongoCursorTimeout)
protected function loadConfig(array $config)
{
$this->config = $config;
- if (array_key_exists('namespaces',$config))
- {
+ if (array_key_exists('namespaces', $config)) {
$this->ns = $config['namespaces'];
}
- $this->defaultContext = $this->getMandatoryKey("defaultContext",$config);
+ $this->defaultContext = $this->getMandatoryKey('defaultContext', $config);
- foreach($this->getMandatoryKey('data_sources', $config) as $source=>$c)
- {
- if(!array_key_exists('type', $c))
- {
+ foreach ($this->getMandatoryKey('data_sources', $config) as $source => $c) {
+ if (!array_key_exists('type', $c)) {
throw new \Tripod\Exceptions\ConfigException("No 'type' set for data source $source");
}
- if(!array_key_exists('connection', $c))
- {
+ if (!array_key_exists('connection', $c)) {
throw new \Tripod\Exceptions\ConfigException("No connection information set for data source $source");
}
$this->dataSources[$source] = $c;
}
- $transactionConfig = $this->getMandatoryKey("transaction_log",$config);
- $this->tConfig["data_source"] = $this->getMandatoryKey('data_source', $transactionConfig, 'transaction_log');
- if(!isset($this->dataSources[$this->tConfig['data_source']]))
- {
+ $transactionConfig = $this->getMandatoryKey('transaction_log', $config);
+ $this->tConfig['data_source'] = $this->getMandatoryKey('data_source', $transactionConfig, 'transaction_log');
+ if (!isset($this->dataSources[$this->tConfig['data_source']])) {
throw new \Tripod\Exceptions\ConfigException("Transaction log data source, " . $this->tConfig['data_source'] . ", was not defined");
}
- $this->tConfig["database"] = $this->getMandatoryKey("database",$transactionConfig,'transaction_log');
- $this->tConfig["collection"] = $this->getMandatoryKey("collection",$transactionConfig,'transaction_log');
+ $this->tConfig["database"] = $this->getMandatoryKey("database", $transactionConfig, 'transaction_log');
+ $this->tConfig["collection"] = $this->getMandatoryKey("collection", $transactionConfig, 'transaction_log');
// A 'pod' corresponds to a logical database
- $this->databases = $this->getMandatoryKey("stores",$config);
+ $this->databases = $this->getMandatoryKey("stores", $config);
$defaultDB = null;
- foreach ($this->databases as $storeName=>$storeConfig)
- {
- $this->dbConfig[$storeName] = array ("data_source"=>$this->getMandatoryKey("data_source",$storeConfig));
- if(isset($storeConfig['database']) && !empty($storeConfig['database']))
- {
+ foreach ($this->databases as $storeName => $storeConfig) {
+ $this->dbConfig[$storeName] = ["data_source" => $this->getMandatoryKey("data_source", $storeConfig)];
+ if (isset($storeConfig['database']) && !empty($storeConfig['database'])) {
$this->dbConfig[$storeName]["database"]=$storeConfig['database'];
- }
- else
- {
+ } else {
$this->dbConfig[$storeName]["database"] = $storeName;
}
- $this->cardinality[$storeName] = array();
- $this->indexes[$storeName] = array();
- $this->podConnections[$storeName] = array();
- if(isset($storeConfig["pods"]))
- {
- foreach($storeConfig["pods"] as $podName=>$podConfig)
- {
+ $this->cardinality[$storeName] = [];
+ $this->indexes[$storeName] = [];
+ $this->podConnections[$storeName] = [];
+ if (isset($storeConfig["pods"])) {
+ foreach ($storeConfig["pods"] as $podName => $podConfig) {
$dataSource = (isset($podConfig['data_source']) ? $podConfig['data_source'] : $storeConfig['data_source']);
$this->podConnections[$storeName][$podName] = $dataSource;
// Set cardinality, also checking against defined namespaces
- if (array_key_exists('cardinality', $podConfig))
- {
+ if (array_key_exists('cardinality', $podConfig)) {
// Test that the namespace exists for each cardinality rule defined
$cardinality = $podConfig['cardinality'];
- foreach ($cardinality as $qname=>$cardinalityValue)
- {
+ foreach ($cardinality as $qname => $cardinalityValue) {
$namespaces = explode(':', $qname);
// just grab the first element
$namespace = array_shift($namespaces);
- if (array_key_exists($namespace, $this->ns))
- {
+ if (array_key_exists($namespace, $this->ns)) {
$this->cardinality[$storeName][$podName][] = $cardinality;
- }
- else
- {
+ } else {
throw new \Tripod\Exceptions\ConfigException("Cardinality '{$qname}' does not have the namespace defined");
}
}
- }
- else
- {
- $this->cardinality[$storeName][$podName] = array();
+ } else {
+ $this->cardinality[$storeName][$podName] = [];
}
- $this->cardinality[$storeName][$podName] = (array_key_exists("cardinality",$podConfig)) ? $podConfig['cardinality'] : array();
+ $this->cardinality[$storeName][$podName] = array_key_exists("cardinality", $podConfig) ? $podConfig['cardinality'] : [];
// Ensure indexes are legal
- if (array_key_exists("indexes",$podConfig))
- {
- $this->indexes[$storeName][$podName] = array();
- foreach($podConfig["indexes"] as $indexName=>$indexFields)
- {
+ if (array_key_exists("indexes", $podConfig)) {
+ $this->indexes[$storeName][$podName] = [];
+ foreach ($podConfig["indexes"] as $indexName => $indexFields) {
// check no more than 1 indexField is an array to ensure Mongo will be able to create compound indexes
- if (count($indexFields)>1)
- {
+ if (count($indexFields) > 1) {
$fieldsThatAreArrays = 0;
- foreach ($indexFields as $field=>$fieldVal)
- {
- $cardinalityField = str_replace('.value','',$field);
- if (!array_key_exists($cardinalityField,$this->cardinality[$storeName][$podName])||$this->cardinality[$storeName][$podName][$cardinalityField]!=1)
- {
+ foreach ($indexFields as $field => $fieldVal) {
+ $cardinalityField = str_replace('.value', '', $field);
+ if (!array_key_exists($cardinalityField, $this->cardinality[$storeName][$podName]) ||
+ $this->cardinality[$storeName][$podName][$cardinalityField] != 1) {
$fieldsThatAreArrays++;
}
- if ($fieldsThatAreArrays>1)
- {
+ if ($fieldsThatAreArrays > 1) {
throw new \Tripod\Exceptions\ConfigException("Compound index $indexName has more than one field with cardinality > 1 - mongo will not be able to build this index");
}
}
@@ -289,29 +274,31 @@ protected function loadConfig(array $config)
}
}
}
- $searchConfig = (array_key_exists("search_config",$storeConfig)) ? $storeConfig["search_config"] : array();
- $this->searchDocSpecs[$storeName] = array();
- if(!empty($searchConfig)){
+ if (isset($storeConfig['batch_sizes'])) {
+ foreach ([OP_TABLES, OP_SEARCH, OP_VIEWS] as $op) {
+ if (isset($storeConfig['batch_sizes'][$op]) && is_numeric($storeConfig['batch_sizes'][$op])) {
+ $this->batchSize[$op] = intval($storeConfig['batch_sizes'][$op]);
+ }
+ }
+ }
+ $searchConfig = array_key_exists("search_config", $storeConfig) ? $storeConfig["search_config"] : [];
+ $this->searchDocSpecs[$storeName] = [];
+ if (!empty($searchConfig)) {
$this->searchProviderClassName[$storeName] = $this->getMandatoryKey('search_provider', $searchConfig, 'search');
// Load search doc specs if search_config is set
$searchDocSpecs = $this->getMandatoryKey('search_specifications', $searchConfig, 'search');
- foreach ($searchDocSpecs as $spec)
- {
- if(!isset($spec[_ID_KEY]))
- {
+ foreach ($searchDocSpecs as $spec) {
+ if (!isset($spec[_ID_KEY])) {
throw new \Tripod\Exceptions\ConfigException("Search document spec does not contain " . _ID_KEY);
}
- if(!isset($spec['from']) || !in_array($spec['from'], $this->getPods($storeName)))
- {
+ if (!isset($spec['from']) || !in_array($spec['from'], $this->getPods($storeName))) {
throw new \Tripod\Exceptions\ConfigException("'" . $spec[_ID_KEY] . "[\"from\"]' property not set or references an undefined pod");
}
- if(!isset($spec['filter']))
- {
+ if (!isset($spec['filter'])) {
throw new \Tripod\Exceptions\ConfigException("'" . $spec[_ID_KEY] . "[\"filter\"]' property not set");
}
- if(!isset($spec['fields']) && !isset($spec['joins']))
- {
+ if (!isset($spec['fields']) && !isset($spec['joins'])) {
throw new \Tripod\Exceptions\ConfigException("'" . $spec[_ID_KEY] . "' contains no 'fields' or 'joins' properties");
}
@@ -334,8 +321,8 @@ protected function loadConfig(array $config)
}
// Load view specs
- $viewSpecs = (array_key_exists("view_specifications",$storeConfig)) ? $storeConfig["view_specifications"] : array();
- $this->viewSpecs[$storeName] = array();
+ $viewSpecs = (array_key_exists("view_specifications",$storeConfig)) ? $storeConfig["view_specifications"] : [];
+ $this->viewSpecs[$storeName] = [];
foreach ($viewSpecs as $spec)
{
if(!isset($spec[_ID_KEY]))
@@ -366,8 +353,8 @@ protected function loadConfig(array $config)
}
// Load table specs
- $tableSpecs = (array_key_exists("table_specifications",$storeConfig)) ? $storeConfig["table_specifications"] : array();
- $this->tableSpecs[$storeName] = array();
+ $tableSpecs = (array_key_exists("table_specifications",$storeConfig)) ? $storeConfig["table_specifications"] : [];
+ $this->tableSpecs[$storeName] = [];
foreach ($tableSpecs as $spec)
{
$this->validateTableSpec($spec);
@@ -763,7 +750,7 @@ protected function validateComputedArithmeticSpec(array $spec, array $availableF
protected function getFieldNamesInSpec(array $spec)
{
- $fieldNames = array();
+ $fieldNames = [];
if(isset($spec['fields']))
{
foreach($spec['fields'] as $field)
@@ -813,7 +800,7 @@ protected function getFieldNamesInSpec(array $spec)
*/
protected function getDefinedPredicatesInSpecs($storename)
{
- $predicates = array();
+ $predicates = [];
$specs = array_merge($this->getTableSpecifications($storename), $this->getSearchDocumentSpecifications($storename));
foreach($specs as $spec)
{
@@ -834,7 +821,7 @@ protected function getDefinedPredicatesInSpecs($storename)
*/
protected function getDefinedPredicatesInSpecBlock(array $block)
{
- $predicates = array();
+ $predicates = [];
// If the spec has a "type" property, include rdf:type
if(isset($block['type']))
{
@@ -933,7 +920,7 @@ protected function getDefinedPredicatesInSpecBlock(array $block)
*/
protected function getPredicateAliasesFromPredicateProperty($predicate)
{
- $predicates = array();
+ $predicates = [];
if(is_string($predicate) && !empty($predicate))
{
$predicates[] = $this->getLabeller()->uri_to_alias($predicate);
@@ -957,7 +944,7 @@ protected function getPredicateAliasesFromPredicateProperty($predicate)
*/
protected function getPredicatesFromPredicateFunctions($array)
{
- $predicates = array();
+ $predicates = [];
if(is_array($array))
{
if(isset($array['predicates']))
@@ -978,7 +965,7 @@ protected function getPredicatesFromPredicateFunctions($array)
*/
protected function getPredicatesFromFilterCondition($filter)
{
- $predicates = array();
+ $predicates = [];
$regex = "/(^|\b)(\w+\:\w+)\.(l|u)(\b|$)/";
foreach($filter as $key=>$condition)
{
@@ -1030,7 +1017,7 @@ public function getDefinedPredicatesInSpec($storename, $specId)
{
return $this->specPredicates[$storename][$specId];
}
- return array();
+ return [];
}
/**
@@ -1144,7 +1131,7 @@ public function getIndexesGroupedByCollection($storeName)
}
// also add the indexes for any views/tables
- $tableIndexes = array();
+ $tableIndexes = [];
foreach ($this->getTableSpecifications($storeName) as $tspec)
{
if (array_key_exists("ensureIndexes",$tspec))
@@ -1152,7 +1139,7 @@ public function getIndexesGroupedByCollection($storeName)
// Indexes should be keyed by data_source
if(!isset($tableIndexes[$tspec['to_data_source']]))
{
- $tableIndexes[$tspec['to_data_source']] = array();
+ $tableIndexes[$tspec['to_data_source']] = [];
}
foreach ($tspec["ensureIndexes"] as $index)
{
@@ -1162,7 +1149,7 @@ public function getIndexesGroupedByCollection($storeName)
}
$indexes[TABLE_ROWS_COLLECTION] = $tableIndexes;
- $viewIndexes = array();
+ $viewIndexes = [];
foreach ($this->getViewSpecifications($storeName) as $vspec)
{
if (array_key_exists("ensureIndexes",$vspec))
@@ -1170,7 +1157,7 @@ public function getIndexesGroupedByCollection($storeName)
// Indexes should be keyed by data_source
if(!isset($viewIndexes[$vspec['to_data_source']]))
{
- $viewIndexes[$vspec['to_data_source']] = array();
+ $viewIndexes[$vspec['to_data_source']] = [];
}
foreach ($vspec["ensureIndexes"] as $index)
{
@@ -1229,7 +1216,7 @@ public function isPodWithinStore($storeName,$pod)
*/
public function getPods($storeName)
{
- return (array_key_exists($storeName,$this->podConnections)) ? array_keys($this->podConnections[$storeName]) : array();
+ return (array_key_exists($storeName,$this->podConnections)) ? array_keys($this->podConnections[$storeName]) : [];
}
/**
@@ -1404,13 +1391,13 @@ public function getSearchDocumentSpecifications($storeName, $type=null, $justRet
if(!isset($this->searchDocSpecs[$storeName]) || empty($this->searchDocSpecs[$storeName]))
{
- return array();
+ return [];
}
- $specs = array();
+ $specs = [];
if(empty($type)){
if($justReturnSpecId){
- $specIds = array();
+ $specIds = [];
foreach($this->searchDocSpecs[$storeName] as $specId=>$spec){
$specIds[] = $specId;
}
@@ -1475,7 +1462,7 @@ public function getTableSpecification($storeName, $tid)
*/
public function getTableSpecifications($storeName)
{
- return (isset($this->tableSpecs[$storeName]) ? $this->tableSpecs[$storeName] : array());
+ return (isset($this->tableSpecs[$storeName]) ? $this->tableSpecs[$storeName] : []);
}
/**
@@ -1486,7 +1473,7 @@ public function getTableSpecifications($storeName)
*/
public function getViewSpecifications($storeName)
{
- return (isset($this->viewSpecs[$storeName]) ? $this->viewSpecs[$storeName] : array());
+ return (isset($this->viewSpecs[$storeName]) ? $this->viewSpecs[$storeName] : []);
}
/**
@@ -1569,7 +1556,7 @@ protected function getLabeller()
*/
private function getSpecificationTypes(Array $specifications, $podName=null)
{
- $types = array();
+ $types = [];
foreach($specifications as $spec){
if(!empty($podName)){
@@ -1659,7 +1646,7 @@ private function isConnectionStringValidForRepSet($connStr)
*/
private function findFieldsInTableSpec($fieldName, $spec)
{
- $fields = array();
+ $fields = [];
if(is_array($spec) && !empty($spec))
{
if(array_key_exists($fieldName, $spec))
@@ -1743,7 +1730,7 @@ protected function getConnectionForDataSource($dataSource)
{
throw new \Tripod\Exceptions\ConfigException("Data source '{$dataSource}' not in configuration");
}
- $connectionOptions = array();
+ $connectionOptions = [];
$ds = $this->dataSources[$dataSource];
$connectionOptions['connectTimeoutMS'] = (isset($ds['connectTimeoutMS']) ? $ds['connectTimeoutMS'] : DEFAULT_MONGO_CONNECT_TIMEOUT_MS);
@@ -1884,17 +1871,17 @@ public function getCollectionForTable($storeName, $tableId, $readPreference = Re
* @throws \Tripod\Exceptions\ConfigException
* @return Collection[]
*/
- public function getCollectionsForTables($storeName, array $tables = array(), $readPreference = ReadPreference::RP_PRIMARY_PREFERRED)
+ public function getCollectionsForTables($storeName, array $tables = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED)
{
if(!isset($this->tableSpecs[$storeName]))
{
- return array();
+ return [];
}
if(empty($tables))
{
$tables = array_keys($this->tableSpecs[$storeName]);
}
- $dataSources = array();
+ $dataSources = [];
foreach($tables as $table)
{
if(isset($this->tableSpecs[$storeName][$table]))
@@ -1907,7 +1894,7 @@ public function getCollectionsForTables($storeName, array $tables = array(), $re
}
}
- $collections = array();
+ $collections = [];
foreach(array_unique($dataSources) as $dataSource)
{
$collections[] = $this->getMongoCollection(
@@ -1925,17 +1912,17 @@ public function getCollectionsForTables($storeName, array $tables = array(), $re
* @throws \Tripod\Exceptions\ConfigException
* @return Collection[]
*/
- public function getCollectionsForViews($storeName, array $views = array(), $readPreference = ReadPreference::RP_PRIMARY_PREFERRED)
+ public function getCollectionsForViews($storeName, array $views = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED)
{
if(!isset($this->viewSpecs[$storeName]))
{
- return array();
+ return [];
}
if(empty($views))
{
$views = array_keys($this->viewSpecs[$storeName]);
}
- $dataSources = array();
+ $dataSources = [];
foreach($views as $view)
{
if(isset($this->viewSpecs[$storeName][$view]))
@@ -1948,7 +1935,7 @@ public function getCollectionsForViews($storeName, array $views = array(), $read
}
}
- $collections = array();
+ $collections = [];
foreach(array_unique($dataSources) as $dataSource)
{
$collections[] = $this->getMongoCollection(
@@ -1966,17 +1953,17 @@ public function getCollectionsForViews($storeName, array $views = array(), $read
* @throws \Tripod\Exceptions\ConfigException
* @return Collection[]
*/
- public function getCollectionsForSearch($storeName, array $searchSpecIds = array(), $readPreference = ReadPreference::RP_PRIMARY_PREFERRED)
+ public function getCollectionsForSearch($storeName, array $searchSpecIds = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED)
{
if(!isset($this->searchDocSpecs[$storeName]))
{
- return array();
+ return [];
}
if(empty($searchSpecIds))
{
$searchSpecIds = array_keys($this->searchDocSpecs[$storeName]);
}
- $dataSources = array();
+ $dataSources = [];
foreach($searchSpecIds as $searchSpec)
{
if(isset($this->searchDocSpecs[$storeName][$searchSpec]))
@@ -1989,7 +1976,7 @@ public function getCollectionsForSearch($storeName, array $searchSpecIds = array
}
}
- $collections = array();
+ $collections = [];
foreach(array_unique($dataSources) as $dataSource)
{
$collections[] = $this->getMongoCollection(
@@ -2187,4 +2174,15 @@ public function serialize()
{
return $this->config;
}
+
+ /**
+ * Return the maximum batch size for async operations
+ *
+ * @param string $operation Async operation, e.g. OP_TABLES, OP_VIEWS
+ * @return integer
+ */
+ public function getBatchSize($operation)
+ {
+ return isset($this->batchSize[$operation]) ? $this->batchSize[$operation] : 1;
+ }
}
diff --git a/src/mongo/Driver.class.php b/src/mongo/Driver.class.php
index f493eaa1..e249d985 100755
--- a/src/mongo/Driver.class.php
+++ b/src/mongo/Driver.class.php
@@ -61,7 +61,7 @@ class Driver extends DriverBase implements \Tripod\IDriver
*
readPreference: The Read preference to set for Mongo: Default is ReadPreference::RP_PRIMARY_PREFERRED
* retriesToGetLock: Retries to do when unable to get lock on a document, default is 20
*/
- public function __construct($podName, $storeName, $opts=array())
+ public function __construct($podName, $storeName, $opts = [])
{
$opts = array_merge(array(
diff --git a/src/mongo/IConfigInstance.php b/src/mongo/IConfigInstance.php
index 8ad37ed2..9e5f1137 100644
--- a/src/mongo/IConfigInstance.php
+++ b/src/mongo/IConfigInstance.php
@@ -281,6 +281,14 @@ public function getCollectionForJobGroups($storeName, $readPreference = ReadPref
*/
public function getTransactionLogDatabase($readPreference = ReadPreference::RP_PRIMARY_PREFERRED);
+ /**
+ * Return the maximum batch size for async operations
+ *
+ * @param string $operation Async operation, e.g. OP_TABLES, OP_VIEWS
+ * @return integer
+ */
+ public function getBatchSize($operation);
+
/**
* @return string
*/
diff --git a/src/mongo/base/CompositeBase.class.php b/src/mongo/base/CompositeBase.class.php
index bf1d050e..08838ac7 100644
--- a/src/mongo/base/CompositeBase.class.php
+++ b/src/mongo/base/CompositeBase.class.php
@@ -2,6 +2,8 @@
namespace Tripod\Mongo\Composites;
+use \Tripod\Mongo\JobGroup;
+
/**
* Class CompositeBase
* @package Tripod\Mongo\Composites
@@ -12,70 +14,65 @@ abstract class CompositeBase extends \Tripod\Mongo\DriverBase implements \Tripod
* @var \Tripod\Mongo\Jobs\ApplyOperation
*/
protected $applyOperation;
+
/**
* Returns an array of ImpactedSubjects based on the subjects and predicates of change
* @param array $subjectsAndPredicatesOfChange
* @param string $contextAlias
* @return \Tripod\Mongo\ImpactedSubject[]
*/
- public function getImpactedSubjects(Array $subjectsAndPredicatesOfChange,$contextAlias)
+ public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, $contextAlias)
{
- $candidates = array();
- $filter = array();
- $subjectsToAlias = array();
- foreach(array_keys($subjectsAndPredicatesOfChange) as $s){
+ $candidates = [];
+ $filter = [];
+ $subjectsToAlias = [];
+ foreach (array_keys($subjectsAndPredicatesOfChange) as $s) {
$resourceAlias = $this->labeller->uri_to_alias($s);
$subjectsToAlias[$s] = $resourceAlias;
// build $filter for queries to impact index
- $filter[] = array(_ID_RESOURCE=>$resourceAlias,_ID_CONTEXT=>$contextAlias);
+ $filter[] = [_ID_RESOURCE=>$resourceAlias, _ID_CONTEXT=>$contextAlias];
}
- $query = array(_ID_KEY=>array('$in'=>$filter));
- $docs = $this->getCollection()->find($query, array(
- 'projection' => array(_ID_KEY=>true, 'rdf:type'=>true)
- ));
+ $query = [_ID_KEY => ['$in' => $filter]];
+ $docs = $this->getCollection()->find(
+ $query,
+ ['projection' => [_ID_KEY => true, 'rdf:type' => true]]
+ );
$types = $this->getTypesInSpecifications();
- if($this->getCollection()->count($query) !== 0 ) {
- foreach($docs as $doc)
- {
+ if ($this->getCollection()->count($query) !== 0) {
+ foreach ($docs as $doc) {
$docResource = $doc[_ID_KEY][_ID_RESOURCE];
$docContext = $doc[_ID_KEY][_ID_CONTEXT];
$docHash = md5($docResource.$docContext);
- $docTypes = array();
- if(isset($doc["rdf:type"])) {
- if(isset($doc["rdf:type"][VALUE_URI])){
- $docTypes[] = $doc["rdf:type"][VALUE_URI];
+ $docTypes = [];
+ if (isset($doc['rdf:type'])) {
+ if (isset($doc['rdf:type'][VALUE_URI])) {
+ $docTypes[] = $doc['rdf:type'][VALUE_URI];
} else {
- foreach($doc["rdf:type"] as $t){
- if(isset($t[VALUE_URI]))
- {
+ foreach ($doc['rdf:type'] as $t) {
+ if (isset($t[VALUE_URI])) {
$docTypes[] = $t[VALUE_URI];
}
}
}
}
- $currentSubjectProperties = array();
- if(isset($subjectsAndPredicatesOfChange[$docResource]))
- {
+ $currentSubjectProperties = [];
+ if (isset($subjectsAndPredicatesOfChange[$docResource])) {
$currentSubjectProperties = $subjectsAndPredicatesOfChange[$docResource];
- }
- elseif(isset($subjectsToAlias[$docResource]) &&
- isset($subjectsAndPredicatesOfChange[$subjectsToAlias[$docResource]]))
- {
+ } elseif (isset($subjectsToAlias[$docResource]) &&
+ isset($subjectsAndPredicatesOfChange[$subjectsToAlias[$docResource]])) {
$currentSubjectProperties = $subjectsAndPredicatesOfChange[$subjectsToAlias[$docResource]];
}
- foreach($docTypes as $type)
- {
- if($this->checkIfTypeShouldTriggerOperation($type, $types, $currentSubjectProperties)) {
- if(!array_key_exists($this->getPodName(), $candidates))
- {
- $candidates[$this->getPodName()] = array();
+ foreach ($docTypes as $type) {
+ if ($this->checkIfTypeShouldTriggerOperation($type, $types, $currentSubjectProperties)) {
+ if (!array_key_exists($this->getPodName(), $candidates)) {
+ $candidates[$this->getPodName()] = [];
}
- if(!array_key_exists($docHash, $candidates[$this->getPodName()])){
- $candidates[$this->getPodName()][$docHash] = array('id'=>$doc[_ID_KEY]);
+ if (!array_key_exists($docHash, $candidates[$this->getPodName()])) {
+ $candidates[$this->getPodName()][$docHash] = ['id'=>$doc[_ID_KEY]];
}
}
}
@@ -83,40 +80,37 @@ public function getImpactedSubjects(Array $subjectsAndPredicatesOfChange,$contex
}
// add to this any composites
- foreach($this->findImpactedComposites($subjectsAndPredicatesOfChange, $contextAlias) as $doc) {
+ foreach ($this->findImpactedComposites($subjectsAndPredicatesOfChange, $contextAlias) as $doc) {
$spec = $this->getSpecification($this->storeName, $doc[_ID_KEY]['type']);
- if(is_array($spec) && array_key_exists('from', $spec)){
- if(!array_key_exists($spec['from'], $candidates))
- {
- $candidates[$spec['from']] = array();
+ if (is_array($spec) && array_key_exists('from', $spec)) {
+ if (!array_key_exists($spec['from'], $candidates)) {
+ $candidates[$spec['from']] = [];
}
$docHash = md5($doc[_ID_KEY][_ID_RESOURCE] . $doc[_ID_KEY][_ID_CONTEXT]);
- if(!array_key_exists($docHash, $candidates[$spec['from']])){
- $candidates[$spec['from']][$docHash] = array(
- 'id'=>array(
+ if (!array_key_exists($docHash, $candidates[$spec['from']])) {
+ $candidates[$spec['from']][$docHash] = [
+ 'id' => [
_ID_RESOURCE=>$doc[_ID_KEY][_ID_RESOURCE],
_ID_CONTEXT=>$doc[_ID_KEY][_ID_CONTEXT],
- )
- );
+ ]
+ ];
}
- if(!array_key_exists('specTypes', $candidates[$spec['from']][$docHash])) {
- $candidates[$spec['from']][$docHash]['specTypes'] = array();
+ if (!array_key_exists('specTypes', $candidates[$spec['from']][$docHash])) {
+ $candidates[$spec['from']][$docHash]['specTypes'] = [];
}
// Save the specification type so we only have to regen resources in that table type
- if(!in_array($doc[_ID_KEY][_ID_TYPE], $candidates[$spec['from']][$docHash]['specTypes']))
- {
+ if (!in_array($doc[_ID_KEY][_ID_TYPE], $candidates[$spec['from']][$docHash]['specTypes'])) {
$candidates[$spec['from']][$docHash]['specTypes'][] = $doc[_ID_KEY][_ID_TYPE];
}
}
}
// convert operations to subjects
- $impactedSubjects = array();
- foreach(array_keys($candidates) as $podName){
- foreach($candidates[$podName] as $candidate)
- {
- $specTypes = (isset($candidate['specTypes']) ? $candidate['specTypes'] : array());
+ $impactedSubjects = [];
+ foreach (array_keys($candidates) as $podName) {
+ foreach ($candidates[$podName] as $candidate) {
+ $specTypes = (isset($candidate['specTypes']) ? $candidate['specTypes'] : []);
$impactedSubjects[] = new \Tripod\Mongo\ImpactedSubject($candidate['id'], $this->getOperationType(), $this->getStoreName(), $podName, $specTypes);
}
}
@@ -128,14 +122,14 @@ public function getImpactedSubjects(Array $subjectsAndPredicatesOfChange,$contex
* Returns an array of the rdf types that will trigger the specification
* @return array
*/
- public abstract function getTypesInSpecifications();
+ abstract public function getTypesInSpecifications();
/**
* @param array $resourcesAndPredicates
* @param string $contextAlias
* @return mixed // @todo: This may eventually return a either a Cursor or array
*/
- public abstract function findImpactedComposites(Array $resourcesAndPredicates,$contextAlias);
+ abstract public function findImpactedComposites(array $resourcesAndPredicates, $contextAlias);
/**
* Returns the specification config
@@ -143,7 +137,7 @@ public abstract function findImpactedComposites(Array $resourcesAndPredicates,$c
* @param string $specId The specification id
* @return array|null
*/
- public abstract function getSpecification($storeName, $specId);
+ abstract public function getSpecification($storeName, $specId);
/**
* Test if the a particular type appears in the array of types associated with a particular spec and that the changeset
@@ -153,20 +147,20 @@ public abstract function getSpecification($storeName, $specId);
* @param array $subjectPredicates
* @return bool
*/
- protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes, Array $subjectPredicates)
+ protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes, array $subjectPredicates)
{
// We don't know if this is an alias or a fqURI, nor what is in the valid types, necessarily
- $types = array($rdfType);
- try
- {
+ $types = [$rdfType];
+ try {
$types[] = $this->labeller->qname_to_uri($rdfType);
+ } catch (\Tripod\Exceptions\LabellerException $e) {
+ // Not a qname, apparently
}
- catch(\Tripod\Exceptions\LabellerException $e) {}
- try
- {
+ try {
$types[] = $this->labeller->uri_to_alias($rdfType);
+ } catch (\Tripod\Exceptions\LabellerException $e) {
+ // Not a declared uri, apparently
}
- catch(\Tripod\Exceptions\LabellerException $e) {}
$intersectingTypes = array_unique(array_intersect($types, $validTypes));
// If views have a matching type *at all*, the operation is triggered
@@ -175,15 +169,38 @@ protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes
/**
* For mocking
- *
+ *
* @return \Tripod\Mongo\Jobs\ApplyOperation
*/
protected function getApplyOperation()
{
- if(!isset($this->applyOperation))
- {
+ if (!isset($this->applyOperation)) {
$this->applyOperation = new \Tripod\Mongo\Jobs\ApplyOperation();
}
return $this->applyOperation;
}
+
+ /**
+ * Queues a batch of ImpactedSubjects in a single ApplyOperation job
+ *
+ * @param \Tripod\Mongo\ImpactedSubject[] $subjects Array of ImpactedSubjects
+ * @param string $queueName Queue name
+ * @param array $jobOptions Job options
+ * @return void
+ */
+ protected function queueApplyJob(array $subjects, $queueName, array $jobOptions)
+ {
+ $this->getApplyOperation()->createJob($subjects, $queueName, $jobOptions);
+ }
+
+ /**
+ * For mocking
+ *
+ * @param string $storeName
+ * @return JobGroup
+ */
+ protected function getJobGroup($storeName)
+ {
+ return new JobGroup($storeName);
+ }
}
diff --git a/src/mongo/delegates/SearchIndexer.class.php b/src/mongo/delegates/SearchIndexer.class.php
index 29f2b175..19a2c675 100644
--- a/src/mongo/delegates/SearchIndexer.class.php
+++ b/src/mongo/delegates/SearchIndexer.class.php
@@ -10,9 +10,10 @@
use Tripod\Mongo\ImpactedSubject;
use Tripod\Mongo\Labeller;
use Tripod\Mongo\Jobs\ApplyOperation;
-use Tripod\Mongo\JobGroup;
use \MongoDB\Driver\ReadPreference;
use \MongoDB\Collection;
+use Tripod\Mongo\Config;
+use Tripod\Mongo\Driver;
/**
* Class SearchIndexer
@@ -44,13 +45,7 @@ public function __construct(\Tripod\Mongo\Driver $tripod, $readPreference = Read
$this->labeller = new Labeller();
$this->stat = $tripod->getStat();
$this->config = $this->getConfigInstance();
- $provider = $this->config->getSearchProviderClassName($this->tripod->getStoreName());
-
- if (class_exists($provider)) {
- $this->configuredProvider = new $provider($this->tripod);
- } else {
- throw new \Tripod\Exceptions\SearchException("Did not recognise Search Provider, or could not find class: $provider");
- }
+ $this->setSearchProvider($this->tripod, $this->config);
$this->readPreference = $readPreference;
}
@@ -97,7 +92,7 @@ public function getOperationType()
*/
public function getSpecification($storeName, $specId)
{
- return $this->config->getSearchDocumentSpecification($storeName,$specId);
+ return $this->config->getSearchDocumentSpecification($storeName, $specId);
}
/**
@@ -107,7 +102,7 @@ public function getSpecification($storeName, $specId)
* @param string $podName
* @param array | string | null $specType
*/
- public function generateAndIndexSearchDocuments($resourceUri, $context, $podName, $specType = array())
+ public function generateAndIndexSearchDocuments($resourceUri, $context, $podName, $specType = [])
{
$mongoCollection = $this->config->getCollectionForCBD($this->storeName, $podName);
@@ -118,42 +113,37 @@ public function generateAndIndexSearchDocuments($resourceUri, $context, $podName
$searchProvider->deleteDocument($resourceUri, $context, $specType); // null means delete all documents for this resource
//2. regenerate search documents for this resource
- $documentsToIndex = array();
+ $documentsToIndex = [];
// first work out what its type is
$query = array("_id"=>array(
'r'=>$this->labeller->uri_to_alias($resourceUri),
'c'=>$this->getContextAlias($context)
));
- $resourceAndType = $mongoCollection->find($query,array(
- 'projection' => array("_id"=>1,"rdf:type"=>1),
- 'maxTimeMS' => $this->config->getMongoCursorTimeout()
- ));
- foreach ($resourceAndType as $rt)
- {
- if (array_key_exists("rdf:type",$rt))
- {
-
- $rdfTypes = array();
+ $resourceAndType = $mongoCollection->find(
+ $query,
+ [
+ 'projection' => ["_id" => 1, "rdf:type" => 1],
+ 'maxTimeMS' => $this->config->getMongoCursorTimeout()
+ ]
+ );
+ foreach ($resourceAndType as $rt) {
+ if (array_key_exists("rdf:type", $rt)) {
+ $rdfTypes = [];
- if (array_key_exists('u',$rt["rdf:type"]))
- {
+ if (array_key_exists('u', $rt["rdf:type"])) {
$rdfTypes[] = $rt["rdf:type"]['u'];
- }
- else
- {
+ } else {
// an array of types
- foreach ($rt["rdf:type"] as $type)
- {
+ foreach ($rt["rdf:type"] as $type) {
$rdfTypes[] = $type['u'];
}
}
$docs = $searchDocGenerator->generateSearchDocumentsBasedOnRdfTypes($rdfTypes, $resourceUri, $context);
- foreach($docs as $d){
+ foreach ($docs as $d) {
$documentsToIndex[] = $d;
}
-
}
}
@@ -192,35 +182,34 @@ public function generateSearchDocuments(
// default collection
$from = (isset($spec["from"])) ? $spec["from"] : $this->podName;
- $types = array();
- if (is_array($spec["type"]))
- {
- foreach ($spec["type"] as $type)
- {
+ $types = [];
+ if (is_array($spec["type"])) {
+ foreach ($spec["type"] as $type) {
$types[] = array("rdf:type.u"=>$this->labeller->qname_to_alias($type));
$types[] = array("rdf:type.u"=>$this->labeller->uri_to_alias($type));
}
- }
- else
- {
+ } else {
$types[] = array("rdf:type.u"=>$this->labeller->qname_to_alias($spec["type"]));
$types[] = array("rdf:type.u"=>$this->labeller->uri_to_alias($spec["type"]));
}
$filter = array('$or'=> $types);
- if (isset($resource))
- {
+ if (isset($resource)) {
$filter["_id"] = array(_ID_RESOURCE=>$this->labeller->uri_to_alias($resource),_ID_CONTEXT=>$contextAlias);
}
- $count = $this->config->getCollectionForCBD($this->getStoreName(), $from)->count($filter);
- $docs = $this->config->getCollectionForCBD($this->getStoreName(), $from)->find($filter, array(
- 'maxTimeMS' => $this->config->getMongoCursorTimeout()
- ));
+ $count = $this->getConfigInstance()->getCollectionForCBD($this->getStoreName(), $from)->count($filter);
+ $docs = $this->getConfigInstance()
+ ->getCollectionForCBD($this->getStoreName(), $from)
+ ->find(
+ $filter,
+ ['maxTimeMS' => $this->getConfigInstance()->getMongoCursorTimeout()]
+ );
$jobOptions = [];
+ $subjects = [];
if ($queueName && !$resourceUri) {
$jobOptions['statsConfig'] = $this->getStatsConfig();
- $jobGroup = new JobGroup($this->storeName);
+ $jobGroup = $this->getJobGroup($this->storeName);
$jobOptions[ApplyOperation::TRACKING_KEY] = $jobGroup->getId()->__toString();
$jobGroup->setJobCount($count);
}
@@ -234,7 +223,12 @@ public function generateSearchDocuments(
array($searchDocumentType)
);
- $this->getApplyOperation()->createJob(array($subject), $queueName, $jobOptions);
+ $subjects[] = $subject;
+ // Queue ApplyOperations jobs in batches rather than individually
+ if (count($subjects) >= $this->getConfigInstance()->getBatchSize(OP_SEARCH)) {
+ $this->queueApplyJob($subjects, $queueName, $jobOptions);
+ $subjects = [];
+ }
} else {
$this->generateAndIndexSearchDocuments(
$doc[_ID_KEY][_ID_RESOURCE],
@@ -245,13 +239,17 @@ public function generateSearchDocuments(
}
}
+ if (!empty($subjects)) {
+ $this->queueApplyJob($subjects, $queueName, $jobOptions);
+ }
+
$t->stop();
$this->timingLog(MONGO_CREATE_TABLE, array(
'type'=>$spec['type'],
'duration'=>$t->result(),
'filter'=>$filter,
'from'=>$from));
- $this->getStat()->timer(MONGO_CREATE_SEARCH_DOC.".$searchDocumentType",$t->result());
+ $this->getStat()->timer(MONGO_CREATE_SEARCH_DOC.".$searchDocumentType", $t->result());
$stat = ['count' => $count];
if (isset($jobOptions[ApplyOperation::TRACKING_KEY])) {
@@ -265,7 +263,7 @@ public function generateSearchDocuments(
* @param string $context
* @return array|mixed
*/
- public function findImpactedComposites(Array $resourcesAndPredicates, $context)
+ public function findImpactedComposites(array $resourcesAndPredicates, $context)
{
return $this->getSearchProvider()->findImpactedDocuments($resourcesAndPredicates, $context);
}
@@ -276,7 +274,7 @@ public function findImpactedComposites(Array $resourcesAndPredicates, $context)
*/
public function deleteSearchDocumentsByTypeId($typeId)
{
- return $this->getSearchProvider()->deleteSearchDocumentsByTypeId($typeId);
+ return $this->getSearchProvider()->deleteSearchDocumentsByTypeId($typeId);
}
@@ -293,7 +291,7 @@ protected function getSearchProvider()
* @param string $context
* @return \Tripod\Mongo\SearchDocuments
*/
- protected function getSearchDocumentGenerator(Collection $collection, $context )
+ protected function getSearchDocumentGenerator(Collection $collection, $context)
{
return new \Tripod\Mongo\SearchDocuments($this->storeName, $collection, $context, $this->tripod->getStat());
}
@@ -302,14 +300,38 @@ protected function getSearchDocumentGenerator(Collection $collection, $context )
* @param array $input
* @return array
*/
- protected function deDupe(Array $input)
+ protected function deDupe(array $input)
{
- $output = array();
- foreach($input as $i){
- if(!in_array($i, $output)){
+ $output = [];
+ foreach ($input as $i) {
+ if (!in_array($i, $output)) {
$output[] = $i;
}
}
return $output;
}
+
+ /**
+ * For mocking
+ *
+ * @param Driver $tripod Mongo Tripod Driver
+ * @param \Tripod\Mongo\IConfigInstance $config Mongo Tripod ConfigInstance
+ * @return void
+ * @throws \Tripod\Exceptions\SearchException If provider class cannot be found
+ */
+ protected function setSearchProvider(Driver $tripod, \Tripod\Mongo\IConfigInstance $config = null)
+ {
+ if (is_null($config)) {
+ $config = $this->getConfigInstance();
+ }
+
+ $provider = $config->getSearchProviderClassName($tripod->getStoreName());
+ if (class_exists($provider)) {
+ $this->configuredProvider = new $provider($tripod);
+ } else {
+ throw new \Tripod\Exceptions\SearchException(
+ "Did not recognise Search Provider, or could not find class: $provider"
+ );
+ }
+ }
}
diff --git a/src/mongo/delegates/Tables.class.php b/src/mongo/delegates/Tables.class.php
index ea8314b4..40b81945 100644
--- a/src/mongo/delegates/Tables.class.php
+++ b/src/mongo/delegates/Tables.class.php
@@ -7,7 +7,6 @@
use \Tripod\Mongo\Jobs\ApplyOperation;
use \Tripod\Mongo\ImpactedSubject;
use \Tripod\Mongo\Labeller;
-use \Tripod\Mongo\JobGroup;
use \MongoDB\Driver\ReadPreference;
use \MongoDB\Collection;
@@ -64,7 +63,7 @@ class Tables extends CompositeBase
/**
* @var array
*/
- protected $temporaryFields = array();
+ protected $temporaryFields = [];
/**
* Construct accepts actual objects rather than strings as this class is a delegate of
@@ -104,7 +103,7 @@ public function update(ImpactedSubject $subject)
$resourceUri = $resource[_ID_RESOURCE];
$context = $resource[_ID_CONTEXT];
- $this->generateTableRowsForResource($resourceUri,$context,$subject->getSpecTypes());
+ $this->generateTableRowsForResource($resourceUri, $context, $subject->getSpecTypes());
}
/**
@@ -126,7 +125,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl
{
$contextAlias = $this->getContextAlias($contextAlias); // belt and braces
- $tablePredicates = array();
+ $tablePredicates = [];
foreach ($this->getConfigInstance()->getTableSpecifications($this->storeName) as $tableSpec) {
if (isset($tableSpec[_ID_KEY])) {
@@ -136,8 +135,8 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl
}
// build a filter - will be used for impactIndex detection and finding direct tables to re-gen
- $tableFilters = array();
- $resourceFilters = array();
+ $tableFilters = [];
+ $resourceFilters = [];
foreach ($resourcesAndPredicates as $resource => $resourcePredicates) {
$resourceAlias = $this->labeller->uri_to_alias($resource);
$id = array(_ID_RESOURCE=>$resourceAlias,_ID_CONTEXT=>$contextAlias);
@@ -149,11 +148,9 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl
} else {
foreach ($tablePredicates as $tableType => $predicates) {
// Only look for table rows if the changed predicates are actually defined in the tablespec
- if(array_intersect($resourcePredicates, $predicates))
- {
- if(!isset($tableFilters[$tableType]))
- {
- $tableFilters[$tableType] = array();
+ if (array_intersect($resourcePredicates, $predicates)) {
+ if (!isset($tableFilters[$tableType])) {
+ $tableFilters[$tableType] = [];
}
// build $filter for queries to impact index
$tableFilters[$tableType][] = $id;
@@ -163,15 +160,11 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl
}
- if(empty($tableFilters) && !empty($resourceFilters))
- {
+ if (empty($tableFilters) && !empty($resourceFilters)) {
$query = array("value."._IMPACT_INDEX=>array('$in'=>$resourceFilters));
- }
- else
- {
- $query = array();
- foreach($tableFilters as $tableType=>$filters)
- {
+ } else {
+ $query = [];
+ foreach ($tableFilters as $tableType => $filters) {
// first re-gen table rows where resources appear in the impact index
$query[] = array("value."._IMPACT_INDEX=>array('$in'=>$filters), '_id.'._ID_TYPE=>$tableType);
}
@@ -193,10 +186,10 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl
if(empty($query))
{
- return array();
+ return [];
}
- $affectedTableRows = array();
+ $affectedTableRows = [];
foreach($this->config->getCollectionsForTables($this->storeName) as $collection)
{
@@ -242,7 +235,7 @@ public function getOperationType()
* @param int $limit
* @return array
*/
- public function getTableRows($tableSpecId,$filter=array(),$sortBy=array(),$offset=0,$limit=10)
+ public function getTableRows($tableSpecId,$filter=[],$sortBy=[],$offset=0,$limit=10)
{
$t = new \Tripod\Timer();
$t->start();
@@ -251,7 +244,7 @@ public function getTableRows($tableSpecId,$filter=array(),$sortBy=array(),$offse
$collection = $this->config->getCollectionForTable($this->storeName, $tableSpecId, $this->readPreference);
- $findOptions = array();
+ $findOptions = [];
if (!empty($limit)) {
$findOptions['skip'] = (int) $offset;
$findOptions['limit'] = (int) $limit;
@@ -261,7 +254,7 @@ public function getTableRows($tableSpecId,$filter=array(),$sortBy=array(),$offse
}
$results = $collection->find($filter, $findOptions);
- $rows = array();
+ $rows = [];
foreach ($results as $doc)
{
if (array_key_exists(_IMPACT_INDEX,$doc['value'])) unset($doc['value'][_IMPACT_INDEX]); // remove impact index from client
@@ -289,7 +282,7 @@ public function getTableRows($tableSpecId,$filter=array(),$sortBy=array(),$offse
* @param array $filter
* @return array
*/
- public function distinct($tableSpecId, $fieldName, array $filter=array())
+ public function distinct($tableSpecId, $fieldName, array $filter=[])
{
$t = new \Tripod\Timer();
$t->start();
@@ -324,7 +317,7 @@ protected function deleteTableRowsForResource($resource, $context=null, $specTyp
$resourceAlias = $this->labeller->uri_to_alias($resource);
$contextAlias = $this->getContextAlias($context);
$query = array(_ID_KEY . '.' . _ID_RESOURCE => $resourceAlias, _ID_KEY . '.' . _ID_CONTEXT => $contextAlias);
- $specNames = array();
+ $specNames = [];
$specTypes = $this->config->getTableSpecifications($this->storeName);
if (empty($specType)) {
$specNames = array_keys($specTypes);
@@ -395,14 +388,14 @@ public function deleteTableRowsByTableId($tableId, $timestamp = null) {
* @param string|null $context
* @param array $specTypes
*/
- protected function generateTableRowsForResource($resource, $context=null, $specTypes=array())
+ protected function generateTableRowsForResource($resource, $context=null, $specTypes=[])
{
$resourceAlias = $this->labeller->uri_to_alias($resource);
$contextAlias = $this->getContextAlias($context);
$this->deleteTableRowsForResource($resource, $context, $specTypes);
- $filter = array();
+ $filter = [];
$filter[] = array("r"=>$resourceAlias,"c"=>$contextAlias);
// now go through the types
@@ -444,7 +437,7 @@ protected function generateTableRowsForResource($resource, $context=null, $specT
* @param array $specTypes
* @return mixed
*/
- public function generateTableRowsForType($rdfType,$subject=null,$context=null, $specTypes = array())
+ public function generateTableRowsForType($rdfType,$subject=null,$context=null, $specTypes = [])
{
$rdfType = $this->labeller->qname_to_alias($rdfType);
$rdfTypeAlias = $this->labeller->uri_to_alias($rdfType);
@@ -456,7 +449,7 @@ public function generateTableRowsForType($rdfType,$subject=null,$context=null, $
}
else
{
- $tableSpecs = array();
+ $tableSpecs = [];
foreach($specTypes as $specType)
{
$spec = $this->getConfigInstance()->getTableSpecification($this->storeName, $specType);
@@ -502,11 +495,11 @@ public function generateTableRows($tableType, $resource = null, $context = null,
{
$t = new \Tripod\Timer();
$t->start();
- $this->temporaryFields = array();
+ $this->temporaryFields = [];
$tableSpec = $this->getConfigInstance()->getTableSpecification($this->storeName, $tableType);
- $collection = $this->config->getCollectionForTable($this->storeName, $tableType);
+ $collection = $this->getConfigInstance()->getCollectionForTable($this->storeName, $tableType);
- if ($tableSpec==null) {
+ if (empty($tableSpec)) {
$this->debugLog("Could not find a table specification for $tableType");
return null;
}
@@ -515,32 +508,37 @@ public function generateTableRows($tableType, $resource = null, $context = null,
$contextAlias = $this->getContextAlias($context);
// default collection
- $from = (isset($tableSpec["from"])) ? $tableSpec["from"] : $this->podName;
+ $from = isset($tableSpec["from"]) ? $tableSpec["from"] : $this->podName;
- $types = array();
+ $types = [];
if (is_array($tableSpec["type"])) {
foreach ($tableSpec["type"] as $type) {
- $types[] = array("rdf:type.u"=>$this->labeller->qname_to_alias($type));
- $types[] = array("rdf:type.u"=>$this->labeller->uri_to_alias($type));
+ $types[] = ["rdf:type.u" => $this->labeller->qname_to_alias($type)];
+ $types[] = ["rdf:type.u" => $this->labeller->uri_to_alias($type)];
}
} else {
- $types[] = array("rdf:type.u"=>$this->labeller->qname_to_alias($tableSpec["type"]));
- $types[] = array("rdf:type.u"=>$this->labeller->uri_to_alias($tableSpec["type"]));
+ $types[] = ["rdf:type.u" => $this->labeller->qname_to_alias($tableSpec["type"])];
+ $types[] = ["rdf:type.u" => $this->labeller->uri_to_alias($tableSpec["type"])];
}
- $filter = array('$or'=> $types);
+ $filter = ['$or' => $types];
if (isset($resource)) {
- $filter["_id"] = array(_ID_RESOURCE=>$this->labeller->uri_to_alias($resource),_ID_CONTEXT=>$contextAlias);
+ $filter["_id"] = [
+ _ID_RESOURCE => $this->labeller->uri_to_alias($resource),
+ _ID_CONTEXT => $contextAlias
+ ];
}
+
// @todo Change this to a command when we upgrade MongoDB to 1.1+
- $count = $this->config->getCollectionForCBD($this->storeName, $from)->count($filter);
- $docs = $this->config->getCollectionForCBD($this->storeName, $from)->find($filter, array(
- 'maxTimeMS' => 1000000
- ));
+ $count = $this->getConfigInstance()->getCollectionForCBD($this->storeName, $from)->count($filter);
+ $docs = $this->getConfigInstance()
+ ->getCollectionForCBD($this->storeName, $from)
+ ->find($filter, ['maxTimeMS' => 1000000]);
$jobOptions = [];
+ $subjects = [];
if ($queueName && !$resource && ($this->stat || !empty($this->statsConfig))) {
$jobOptions['statsConfig'] = $this->getStatsConfig();
- $jobGroup = new JobGroup($this->storeName);
+ $jobGroup = $this->getJobGroup($this->storeName);
$jobOptions[ApplyOperation::TRACKING_KEY] = $jobGroup->getId()->__toString();
$jobGroup->setJobCount($count);
}
@@ -554,8 +552,11 @@ public function generateTableRows($tableType, $resource = null, $context = null,
$from,
array($tableType)
);
-
- $this->getApplyOperation()->createJob(array($subject), $queueName, $jobOptions);
+ $subjects[] = $subject;
+ if (count($subjects) >= $this->getConfigInstance()->getBatchSize(OP_TABLES)) {
+ $this->queueApplyJob($subjects, $queueName, $jobOptions);
+ $subjects = [];
+ }
} else {
// set up ID
$generatedRow = [
@@ -569,12 +570,12 @@ public function generateTableRows($tableType, $resource = null, $context = null,
// everything must go in the value object todo: this is a hang over from map reduce days, engineer out once we have stability on new PHP method for M/R
$value = ['_id' => $doc['_id']];
$this->addIdToImpactIndex($doc['_id'], $value); // need to add the doc to the impact index to be consistent with views/search etc. this is needed for discovering impacted operations
- $this->addFields($doc,$tableSpec,$value);
+ $this->addFields($doc, $tableSpec, $value);
if (isset($tableSpec['joins'])) {
- $this->doJoins($doc,$tableSpec['joins'],$value,$from,$contextAlias);
+ $this->doJoins($doc, $tableSpec['joins'], $value, $from, $contextAlias);
}
if (isset($tableSpec['counts'])) {
- $this->doCounts($doc,$tableSpec['counts'],$value);
+ $this->doCounts($doc, $tableSpec['counts'], $value);
}
if (isset($tableSpec['computed_fields'])) {
@@ -588,13 +589,17 @@ public function generateTableRows($tableType, $resource = null, $context = null,
}
}
+ if (!empty($subjects)) {
+ $this->queueApplyJob($subjects, $queueName, $jobOptions);
+ }
+
$t->stop();
$this->timingLog(MONGO_CREATE_TABLE, array(
'type'=>$tableSpec['type'],
'duration'=>$t->result(),
'filter'=>$filter,
'from'=>$from));
- $this->getStat()->timer(MONGO_CREATE_TABLE.".$tableType",$t->result());
+ $this->getStat()->timer(MONGO_CREATE_TABLE.".$tableType", $t->result());
$stat = ['count' => $count];
if (isset($jobOptions[ApplyOperation::TRACKING_KEY])) {
@@ -641,7 +646,7 @@ protected function truncatingSave(Collection $collection, array $generatedRow)
protected function truncateFields(Collection $collection, array &$generatedRow)
{
// Find the name of any indexed fields
- $indexedFields = array();
+ $indexedFields = [];
$indexesGroupedByCollection = $this->config->getIndexesGroupedByCollection($this->storeName);
if (isset($indexesGroupedByCollection) && isset($indexesGroupedByCollection[$collection->getCollectionName()]))
{
@@ -911,7 +916,7 @@ protected function rewriteVariableValue($value, array &$dest, $setType=null)
$function = array_keys($value);
return $this->getComputedValue($function[0], $value, $dest);
}
- $aryValue = array();
+ $aryValue = [];
foreach($value as $v)
{
$aryValue[] = $this->rewriteVariableValue($v, $dest);
@@ -1129,7 +1134,7 @@ protected function addFields($source,$spec,&$dest)
*/
protected function generateValues($source, $f, $predicate, &$dest)
{
- $values = array();
+ $values = [];
if (isset($source[$predicate][VALUE_URI]) && !empty($source[$predicate][VALUE_URI]))
{
$values[] = $source[$predicate][VALUE_URI];
@@ -1175,7 +1180,7 @@ protected function generateValues($source, $f, $predicate, &$dest)
{
// convert from single value to array of values
$existingVal = $dest[$f['fieldName']];
- $dest[$f['fieldName']] = array();
+ $dest[$f['fieldName']] = [];
$dest[$f['fieldName']][] = $existingVal;
$dest[$f['fieldName']][] = $v;
}
@@ -1190,7 +1195,7 @@ protected function generateValues($source, $f, $predicate, &$dest)
*/
protected function getPredicateFunctions($array)
{
- $predicateFunctions = array();
+ $predicateFunctions = [];
if(is_array($array))
{
if(isset($array['predicates']))
@@ -1217,7 +1222,7 @@ protected function getPredicateFunctions($array)
* @throws \Exception
* @return mixed
*/
- private function applyModifier($modifier, $value, $options = array())
+ private function applyModifier($modifier, $value, $options = [])
{
try
{
@@ -1271,7 +1276,7 @@ protected function doJoins($source,$joins,&$dest,$from,$contextAlias)
// to join on it. However, we need to think about different combinations of
// nested joins in different points of the view spec and see if this would
// complicate things. Needs a unit test or two.
- $joinUris = array();
+ $joinUris = [];
if (isset($source[$predicate][VALUE_URI]))
{
// single value for join
@@ -1291,7 +1296,7 @@ protected function doJoins($source,$joins,&$dest,$from,$contextAlias)
}
}
- $recursiveJoins = array();
+ $recursiveJoins = [];
$collection = (isset($ruleset['from'])
? $this->config->getCollectionForCBD($this->storeName, $ruleset['from'])
: $this->config->getCollectionForCBD($this->storeName, $from)
diff --git a/src/mongo/delegates/Views.class.php b/src/mongo/delegates/Views.class.php
index c1ba8f1b..4a462b69 100644
--- a/src/mongo/delegates/Views.class.php
+++ b/src/mongo/delegates/Views.class.php
@@ -7,7 +7,6 @@
use \Tripod\Mongo\Labeller;
use \MongoDB\Driver\ReadPreference;
use \MongoDB\Collection;
-use Tripod\Mongo\JobGroup;
/**
* Class Views
@@ -153,7 +152,7 @@ public function getViews(Array $filter, $viewType)
{
if (strpos($predicate,'$')===0)
{
- $values = array();
+ $values = [];
foreach ($object as $obj)
{
foreach ($obj as $p=>$o) $values[] = array('value.'._GRAPHS.'.'.$p=>$o);
@@ -240,7 +239,7 @@ public function getViewForResources(Array $resources,$viewType,$context=null)
$missingSubjects = array_diff($resources,$returnedSubjects);
if (!empty($missingSubjects))
{
- $regrabResources = array();
+ $regrabResources = [];
foreach($missingSubjects as $missingSubject)
{
$viewSpec = $this->getConfigInstance()->getViewSpecification($this->storeName, $viewType);
@@ -285,7 +284,7 @@ public function getViewForResources(Array $resources,$viewType,$context=null)
private function createTripodViewIdsFromResourceUris($resourceUriOrArray,$context,$viewType)
{
$contextAlias = $this->getContextAlias($context);
- $ret = array();
+ $ret = [];
foreach($resourceUriOrArray as $resource)
{
$ret[] = array("r"=>$this->labeller->uri_to_alias($resource),"c"=>$contextAlias,"type"=>$viewType);
@@ -303,7 +302,7 @@ public function generateViews($resources,$context=null)
$contextAlias = $this->getContextAlias($context);
// build a filter - will be used for impactIndex detection and finding direct views to re-gen
- $filter = array();
+ $filter = [];
foreach ($resources as $resource)
{
$resourceAlias = $this->labeller->uri_to_alias($resource);
@@ -431,13 +430,13 @@ public function generateView($viewId, $resource = null, $context = null, $queueN
$t->start();
$from = $this->getFromCollectionForViewSpec($viewSpec);
- $collection = $this->config->getCollectionForView($this->storeName, $viewId);
+ $collection = $this->getConfigInstance()->getCollectionForView($this->storeName, $viewId);
if (!isset($viewSpec['joins'])) {
throw new \Tripod\Exceptions\ViewException('Could not find any joins in view specification - usecase better served with select()');
}
- $types = array(); // this is used to filter the CBD table to speed up the view creation
+ $types = []; // this is used to filter the CBD table to speed up the view creation
if (is_array($viewSpec["type"])) {
foreach ($viewSpec["type"] as $type) {
$types[] = array("rdf:type.u"=>$this->labeller->qname_to_alias($type));
@@ -454,17 +453,18 @@ public function generateView($viewId, $resource = null, $context = null, $queueN
}
// @todo Change this to a command when we upgrade MongoDB to 1.1+
- $count = $this->config->getCollectionForCBD($this->storeName, $from)->count($filter);
- $docs = $this->config->getCollectionForCBD($this->storeName, $from)->find($filter, array(
+ $count = $this->getConfigInstance()->getCollectionForCBD($this->storeName, $from)->count($filter);
+ $docs = $this->getConfigInstance()->getCollectionForCBD($this->storeName, $from)->find($filter, array(
'maxTimeMS' => $this->getConfigInstance()->getMongoCursorTimeout()
));
$jobOptions = [];
+ $subjects = [];
if ($queueName && !$resource) {
$jobOptions['statsConfig'] = $this->getStatsConfig();
- $jobGroup = new JobGroup($this->storeName);
+ $jobGroup = $this->getJobGroup($this->storeName);
$jobOptions[ApplyOperation::TRACKING_KEY] = $jobGroup->getId()->__toString();
$jobGroup->setJobCount($count);
}
@@ -477,8 +477,11 @@ public function generateView($viewId, $resource = null, $context = null, $queueN
$from,
array($viewId)
);
-
- $this->getApplyOperation()->createJob(array($subject), $queueName, $jobOptions);
+ $subjects[] = $subject;
+ if (count($subjects) >= $this->getConfigInstance()->getBatchSize(OP_VIEWS)) {
+ $this->queueApplyJob($subjects, $queueName, $jobOptions);
+ $subjects = [];
+ }
} else {
// Set up view meta information
$generatedView = [
@@ -489,9 +492,9 @@ public function generateView($viewId, $resource = null, $context = null, $queueN
],
\_CREATED_TS => \Tripod\Mongo\DateUtil::getMongoDate()
];
- $value = array(); // everything must go in the value object todo: this is a hang over from map reduce days, engineer out once we have stability on new PHP method for M/R
+ $value = []; // everything must go in the value object todo: this is a hang over from map reduce days, engineer out once we have stability on new PHP method for M/R
- $value[_GRAPHS] = array();
+ $value[_GRAPHS] = [];
$buildImpactIndex=true;
if (isset($viewSpec['ttl'])) {
@@ -516,6 +519,10 @@ public function generateView($viewId, $resource = null, $context = null, $queueN
}
}
+ if (!empty($subjects)) {
+ $this->queueApplyJob($subjects, $queueName, $jobOptions);
+ }
+
$t->stop();
$this->timingLog(MONGO_CREATE_VIEW, array(
'view'=>$viewSpec['type'],
@@ -557,7 +564,7 @@ protected function doJoins($source, $joins, &$dest, $from, $contextAlias, $build
// to join on it. However, we need to think about different combinations of
// nested joins in different points of the view spec and see if this would
// complicate things. Needs a unit test or two.
- $joinUris = array();
+ $joinUris = [];
if (isset($source[$predicate][VALUE_URI]))
{
// single value for join
@@ -578,7 +585,7 @@ protected function doJoins($source, $joins, &$dest, $from, $contextAlias, $build
}
}
- $recursiveJoins = array();
+ $recursiveJoins = [];
$collection = (
isset($ruleset['from'])
? $this->config->getCollectionForCBD($this->storeName, $ruleset['from'])
@@ -682,7 +689,7 @@ protected function matchesFilter($linkMatchType, $linkMatchValue, $filterType, $
*/
protected function extractProperties($source,$viewSpec,$from)
{
- $obj = array();
+ $obj = [];
if (isset($viewSpec['include']))
{
$obj['_id'] = $source['_id'];
@@ -742,7 +749,7 @@ protected function extractProperties($source,$viewSpec,$from)
}
if(isset($source[$p]) && isset($source[$p][$i]))
{
- if (!isset($obj[$p])) $obj[$p] = array();
+ if (!isset($obj[$p])) $obj[$p] = [];
$obj[$p][] = $source[$p][$i];
}
}
@@ -770,7 +777,7 @@ protected function extractProperties($source,$viewSpec,$from)
}
if($val && isset($val[$i]))
{
- if (!$obj[$p]) $obj[$p] = array();
+ if (!$obj[$p]) $obj[$p] = [];
$obj[$p][] = $val[$i];
}
}
diff --git a/test/unit/mongo/MongoTripodSearchIndexerTest.php b/test/unit/mongo/MongoTripodSearchIndexerTest.php
index 7b9c86ef..322f5f8a 100644
--- a/test/unit/mongo/MongoTripodSearchIndexerTest.php
+++ b/test/unit/mongo/MongoTripodSearchIndexerTest.php
@@ -13,8 +13,7 @@ protected function setUp()
parent::setUp();
$this->tripod = new \Tripod\Mongo\Driver("CBD_testing", "tripod_php_testing", array("async"=>array(OP_VIEWS=>true, OP_TABLES=>true, OP_SEARCH=>false)));
- foreach(\Tripod\Config::getInstance()->getCollectionsForSearch($this->tripod->getStoreName()) as $collection)
- {
+ foreach (\Tripod\Config::getInstance()->getCollectionsForSearch($this->tripod->getStoreName()) as $collection) {
$collection->drop();
}
$this->loadResourceDataViaTripod();
@@ -499,4 +498,85 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject()
$this->assertEquals($expectedImpactedSubjects, $impactedSubjects);
}
-}
\ No newline at end of file
+ public function testBatchSearchDocumentsGeneration()
+ {
+ $count = 234;
+ $docs = [];
+
+ $configOptions = json_decode(file_get_contents(__DIR__ . '/data/config.json'), true);
+
+ for ($i = 0; $i < $count; $i++) {
+ $docs[] = ['_id' => ['r' => 'tenantLists:batch' . $i, 'c' => 'tenantContexts:DefaultGraph']];
+ }
+
+ $fakeCursor = new ArrayIterator($docs);
+ /** @var \PHPUnit_Framework_MockObject_MockObject|TripodTestConfig $configInstance */
+ $configInstance = $this->getMockBuilder('TripodTestConfig')
+ ->setMethods(['getCollectionForCBD'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configInstance->loadConfig($configOptions);
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\MongoDB\Collection $collection */
+ $collection = $this->getMockBuilder('\MongoDB\Collection')
+ ->setMethods(['count', 'find'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $collection->expects($this->atLeastOnce())->method('count')->willReturn($count);
+ $collection->expects($this->atLeastOnce())->method('find')->willReturn($fakeCursor);
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\Tripod\Mongo\JobGroup $jobGroup */
+ $jobGroup = $this->getMockBuilder('\Tripod\Mongo\JobGroup')
+ ->setMethods(['setJobCount'])
+ ->setConstructorArgs(['tripod_php_testing'])
+ ->getMock();
+ $jobGroup->expects($this->once())->method('setJobCount')->with($count);
+
+ $configInstance->expects($this->atLeastOnce())->method('getCollectionForCBD')->willReturn($collection);
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\Tripod\Mongo\Driver $tripod */
+ $tripod = $this->getMockBuilder('\Tripod\Mongo\Driver')
+ ->setMethods(['getConfigInstance',])
+ ->setConstructorArgs(['tripod_php_testing', 'CBD_testing'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\Tripod\Mongo\Composites\SearchIndexer $search */
+ $search = $this->getMockBuilder('\Tripod\Mongo\Composites\SearchIndexer')
+ ->setMethods(['setSearchProvider', 'getConfigInstance', 'queueApplyJob', 'getJobGroup'])
+ ->setConstructorArgs([$tripod])
+ ->getMock();
+ $search->expects($this->atLeastOnce())->method('getConfigInstance')->willReturn($configInstance);
+ $search->expects($this->once())->method('getJobGroup')->willReturn($jobGroup);
+ $search->expects($this->exactly(3))->method('queueApplyJob')
+ ->withConsecutive(
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(100)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(100)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(34)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ]
+ );
+ $search->generateSearchDocuments('i_search_list', null, null, 'TESTQUEUE');
+ }
+}
diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php
index dbef6ec7..c184309a 100644
--- a/test/unit/mongo/MongoTripodTablesTest.php
+++ b/test/unit/mongo/MongoTripodTablesTest.php
@@ -1,6 +1,7 @@
tripodTransactionLog = new \Tripod\Mongo\TransactionLog();
$this->tripodTransactionLog->purgeAllTransactions();
- $this->tripod = new \Tripod\Mongo\Driver($this->defaultPodName, $this->defaultStoreName, array("async"=>array(OP_VIEWS=>false, OP_TABLES=>false, OP_SEARCH=>false)));
+ $this->tripod = new \Tripod\Mongo\Driver(
+ $this->defaultPodName,
+ $this->defaultStoreName,
+ ["async" => [OP_VIEWS=>false, OP_TABLES => false, OP_SEARCH => false]]
+ );
$this->getTripodCollection($this->tripod)->drop();
$this->tripod->setTransactionLog($this->tripodTransactionLog);
$this->loadResourceDataViaTripod();
- $this->tablesConstParams = array($this->tripod->getStoreName(),$this->getTripodCollection($this->tripod),'http://talisaspire.com/');
+ $this->tablesConstParams = [
+ $this->tripod->getStoreName(),
+ $this->getTripodCollection($this->tripod),
+ 'http://talisaspire.com/'
+ ];
- $this->tripodTables = new \Tripod\Mongo\Composites\Tables($this->tripod->getStoreName(),$this->getTripodCollection($this->tripod),null); // pass null context, should default to http://talisaspire.com
+ $this->tripodTables = new \Tripod\Mongo\Composites\Tables(
+ $this->tripod->getStoreName(),
+ $this->getTripodCollection($this->tripod),
+ null // pass null context, should default to http://talisaspire.com
+ );
// purge tables
foreach (\Tripod\Config::getInstance()->getCollectionsForTables($this->tripod->getStoreName()) as $collection) {
@@ -303,6 +316,74 @@ public function testGenerateTableRows()
$this->assertTrue(isset($result['isbn13']),"Result does not contain isbn13");
}
+ public function testBatchTableRowGeneration()
+ {
+ $count = 234;
+ $docs = [];
+
+ $configOptions = json_decode(file_get_contents(__DIR__ . '/data/config.json'), true);
+
+ for ($i = 0; $i < $count; $i++) {
+ $docs[] = ['_id' => ['r' => 'tenantLists:batch' . $i, 'c' => 'tenantContexts:DefaultGraph']];
+ }
+
+ $fakeCursor = new ArrayIterator($docs);
+ /** @var \PHPUnit_Framework_MockObject_MockObject|TripodTestConfig $configInstance */
+ $configInstance = $this->getMockBuilder('TripodTestConfig')
+ ->setMethods(['getCollectionForTable', 'getCollectionForCBD'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configInstance->loadConfig($configOptions);
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\MongoDB\Collection $collection */
+ $collection = $this->getMockBuilder('\MongoDB\Collection')
+ ->setMethods(['count', 'find'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $collection->expects($this->atLeastOnce())->method('count')->willReturn($count);
+ $collection->expects($this->atLeastOnce())->method('find')->willReturn($fakeCursor);
+
+ $configInstance->expects($this->atLeastOnce())->method('getCollectionForCBD')->willReturn($collection);
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\Tripod\Mongo\Composites\Tables $tables */
+ $tables = $this->getMockBuilder('\Tripod\Mongo\Composites\Tables')
+ ->setMethods(['getConfigInstance', 'queueApplyJob'])
+ ->setConstructorArgs(['tripod_php_testing', $collection, 'tenantContexts:DefaultGraph'])
+ ->getMock();
+ $tables->expects($this->atLeastOnce())->method('getConfigInstance')->willReturn($configInstance);
+ $tables->expects($this->exactly(3))->method('queueApplyJob')
+ ->withConsecutive(
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(100)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(100)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(34)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ]
+ );
+ $tables->generateTableRows('t_resource', null, null, 'TESTQUEUE');
+ }
+
public function testGetTableRowsSort()
{
$this->tripodTables->generateTableRows("t_resource");
diff --git a/test/unit/mongo/MongoTripodViewsTest.php b/test/unit/mongo/MongoTripodViewsTest.php
index 2bf3c513..3b987edf 100644
--- a/test/unit/mongo/MongoTripodViewsTest.php
+++ b/test/unit/mongo/MongoTripodViewsTest.php
@@ -2276,4 +2276,135 @@ public function testDeleteViewsByViewIdWithTimestamp()
$this->assertEquals(30, $views->deleteViewsByViewId('v_resource_full', $timestamp));
}
+
+ public function testBatchViewGeneration()
+ {
+ $count = 234;
+ $docs = [];
+
+ $configOptions = json_decode(file_get_contents(__DIR__ . '/data/config.json'), true);
+
+ for ($i = 0; $i < $count; $i++) {
+ $docs[] = ['_id' => ['r' => 'tenantLists:batch' . $i, 'c' => 'tenantContexts:DefaultGraph']];
+ }
+
+ $fakeCursor = new ArrayIterator($docs);
+ /** @var \PHPUnit_Framework_MockObject_MockObject|TripodTestConfig $configInstance */
+ $configInstance = $this->getMockBuilder('TripodTestConfig')
+ ->setMethods(['getCollectionForView', 'getCollectionForCBD'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configInstance->loadConfig($configOptions);
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\MongoDB\Collection $collection */
+ $collection = $this->getMockBuilder('\MongoDB\Collection')
+ ->setMethods(['count', 'find'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $collection->expects($this->atLeastOnce())->method('count')->willReturn($count);
+ $collection->expects($this->atLeastOnce())->method('find')->willReturn($fakeCursor);
+
+ $configInstance->expects($this->atLeastOnce())->method('getCollectionForCBD')->willReturn($collection);
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject|\Tripod\Mongo\Composites\Views $views */
+ $views = $this->getMockBuilder('\Tripod\Mongo\Composites\Views')
+ ->setMethods(['getConfigInstance', 'queueApplyJob'])
+ ->setConstructorArgs(['tripod_php_testing', $collection, 'tenantContexts:DefaultGraph'])
+ ->getMock();
+ $views->expects($this->atLeastOnce())->method('getConfigInstance')->willReturn($configInstance);
+ $views->expects($this->exactly(10))->method('queueApplyJob')
+ ->withConsecutive(
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(25)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ],
+ [
+ $this->logicalAnd(
+ $this->isType('array'),
+ $this->containsOnlyInstancesOf('\Tripod\Mongo\ImpactedSubject'),
+ $this->countOf(9)
+ ),
+ 'TESTQUEUE',
+ $this->isType('array')
+ ]
+ );
+ $views->generateView('v_resource_full', null, null, 'TESTQUEUE');
+ }
}