Excessive Metadata when getting all states in Test Corda vault - spring

Im testing a Corda 4 Cordapp and set up a spring web server to make api calls to my cordapps. I have one api called named ```get-all-contract1-states`` which does exactly what it says. It gets all of my contract1 states in the vault.
When I call this function, it does return the states, but also returns an excessive amount of repetitive metadata making the output for 1 state more than 600k lines long.
#GetMapping(value = "/get-contract1-states", produces = arrayOf(MediaType.APPLICATION_JSON_VALUE))
fun getContract1s() = rpcOps.vaultQueryBy(criteria = VaultQueryCriteria(status = Vault.StateStatus.ALL), paging = PageSpecification(DEFAULT_PAGE_NUM, 200), sorting = Sort(emptySet()), contractStateType = contract1State::class.java).states
Most of the repetitive metadata (which makes up about 85% of the 600k lines) is at the end of the Json regarding "zero":false,"one":false,"fieldSize":256,"fieldName":"SecP256R1Field". Are there any flags, options, or simply any way to get back a clean version of the contract without so much excess data. I only care about the variables from the contract, nothing more.

What you currently have will return you a collection of:
data class Page<out T : ContractState>(val states: List<StateAndRef<T>>,
val statesMetadata: List<StateMetadata>,
val totalStatesAvailable: Long,
val stateTypes: StateStatus,
val otherResults: List<Any>)
Hence why you're getting all the metadata. What you're after in this data object is states (which actually returns StateAndRef) and then just state within each.
The following code should get you what you're after:
#GetMapping(value = "/get-contract1-states", produces = arrayOf(MediaType.APPLICATION_JSON_VALUE))
fun getContract1s() = proxy.vaultQueryBy(criteria = QueryCriteria.VaultQueryCriteria(status =
Vault.StateStatus.ALL), paging = PageSpecification(DEFAULT_PAGE_NUM, 200),
sorting = Sort(emptySet()), contractStateType = IOUState::class.java).states.map { it.state.data }
Note: the key bit here is the mapping to state.data

Related

How to get nested objects inside entity

I'm new with unit tests. I'm trying test Service Layer in a SPRING APP.
Good, i have any relationships in my Service.
VirtualDatacenterModel vdc = vdcRepository.findById(vmDTO.getVdc()).orElseThrow(() -> new ClientException("Invalid VDC id"));
DataCenterModel dc = vdc.getDatacenter();
String vmName = vdc.getTenant().getName() + "_[" + vmDTO.getName() + "]";
In my test i used MOCKITO, dependencies already is mocked, then i cannot see where is wrong
CreateVmDTO vmDTO = Mockito.mock(CreateVmDTO.class);
VmModel vm = Mockito.mock(VmModel.class);
VirtualDatacenterModel vdc = Mockito.mock(VirtualDatacenterModel.class, Mockito.RETURNS_DEEP_STUBS);
TenantModel tenant = Mockito.mock(TenantModel.class);
Mockito.when(vmRepository.save(vm)).thenReturn(new VmModel());
Mockito.when(vdcRepository.findById(vmDTO.getVdc())).thenReturn(Optional.of(new VirtualDatacenterModel()));
Mockito.doReturn(tenant).when(vdc).getTenant();
Mockito.when(vdc.getTenant().getName()).thenReturn("Olivia");
VmModel vmReturn = vmService.createVM(vmDTO);
And i receive NullPointerException, i probably don't know how to use Mockito correctly
You can only mock one action at the time, the following line will certainly be a problem:
Mockito.when(vdcRepository.findById(vmDTO.getVdc())).thenReturn(Optional.of(new VirtualDatacenterModel()));
cause vmDTO.getVdc() will return a null pointer. (vmDTO is a mocked object itself, and has no instruction set for that call). Assuming vmDTO.getVdc() returns the vdc, you can fix as follows:
CreateVmDTO vmDTO = Mockito.mock(CreateVmDTO.class);
VmModel vm = Mockito.mock(VmModel.class);
VirtualDatacenterModel vdc = Mockito.mock(VirtualDatacenterModel.class, Mockito.RETURNS_DEEP_STUBS);
//example fix:
Mockito.when(vmDTO.getVdc()).thenReturn(vdc);
TenantModel tenant = Mockito.mock(TenantModel.class);
Mockito.when(vmRepository.save(vm)).thenReturn(new VmModel());
//also you can do directly:
Mockito.when(vdcRepository.findById(vdc)).thenReturn(Optional.of(new VirtualDatacenterModel()));
Mockito.doReturn(tenant).when(vdc).getTenant();
Mockito.when(vdc.getTenant().getName()).thenReturn("Olivia");
VmModel vmReturn = vmService.createVM(vmDTO);
Also the naming of your methods throws me off:
You have a method vdcRepository.findById, but your input is a vdc object, and not an id? Either the naming is confusing or your input is wrong. If getVdc returns an Id, then you can fix the code by mocking the return of an Id (rename the method to getVdcId or something).
Note: Personally, I seldom mock a DTO. It is just as easy to make the real DTO object, since they often come with a builder or getter/setter.

Spring Webflux: Extract value from Mono

I am new to spring webflux and am trying to perform some arithmetic on the values of two monos. I have a product service that retrieves account information by calling an account service via webClient. I want to determine if the current balance of the account is greater than or equal to the price of the product.
Mono<Account> account = webClientBuilder.build().get().uri("http://account-service/user/accounts/{userId}/",userId)
.retrieve().bodyToMono(Account.class);
//productId is a path variable on method
Mono<Product> product =this.productService.findById(productId);
When I try to block the stream I get an error
block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2
//Causes Error
Double accountBalance = account.map(a->a.getBalance()).block():
Double productPrice = product.map(p->p.getPrice()).block();
///Find difference, send response accordingly....
Is this the correct approach of there is another, better way to achieve this? I was also thinking something along the lines of:
Mono<Double> accountBalance = account.map(a->a.getBalance()):
Mono<Double> productPrice = product.map(p->p.getPrice());
Mono<Double> res = accountBalance.zipWith(productPrice,(b,p)-> b-p);
//Something after this.....
You can't use block method on main reactor thread. This is forbidden. block may work when publish mono on some other thread but it's not a case.
Basically your approach with zipping two monos is correct. You can create some helper method to do calculation on them. In your case it may look like:
public boolean isAccountBalanceGreater(Account acc, Product prd) {
return acc.getBalance() >= prd.getPrice();
}
And then in your Mono stream you can pass method reference and make it more readable.
Mono<Boolean> result = account.zipWith(productPrice, this::isAccountBalanceGreater)
The question is what you want to do with that information later. If you want return to your controller just true or false that's fine. Otherwise you may need some other mappings, zippings etc.
Update
return account.zipWith(productPrice, this::createResponse);
...
ResponseEntity createResponse(Account acc, Product prd) {
int responseCode = isAccountBalanceGreater(acc, prd) ? 200 : 500;
return ResponseEntity.status(responseCode).body(prd);
}

querying data with micrometer

We have this fancy monitoring system to which our spring-boot services are posting metrics to an influx DB with micrometer. There's a nice grafana frontend, but the problem is that we're now at a stage where we have to have some of these metrics available in other services to reason on.
The whole system was set up by my predecessor, and my current understanding of it is practically zero. I can add and post new metrics, but I can't for the life of me get anything out of it.
Here's a short example:
Our gateway increments the counter for each image that a camera posts to it. The definition of the counter looks like this:
private val imageCounters = mutableMapOf<String, Counter>()
private val imageCounter = { camera: String ->
imageCounters.getOrPut(camera) {
registry.counter("gateway.image.counter", "camera", camera)
}
And the counter is incremented in the code like this:
imageCounter("placeholder-id").increment()
Now we're improving our billing, and the billing service needs to know how many images for a certain camera went through the gateway. So naturally the first thing I try looks like this:
class MonitoringService(val metrics: MeterRegistry) {
private val log = logger()
private val imageCounters = mutableMapOf<String, Counter>()
private val imageCounter = { camera: String ->
imageCounters.getOrPut(camera) {
metrics.counter("gateway.image.counter", "camera", camera)
}
}
fun test() {
val test = imageCounter("16004").count()
val bugme = true
log.info("influx test: $test")
}
}
There's two problems with this: First off it always returns zero, so obviously I'm doing it wrong. I just can't figure out what it is.
Second, even if it would return a reasonable value, I don't see a way to limit this by time (I'll usually need the number of images uploaded during the current month).
What worries me is that while I can find a lot of documentation on how to post data with micrometer, I can't seem to find any documentation on how to query. Is Micrometer only designed to post monitoring data, but not query it? the .getOrPut() method would indicate it can do both, but since querying data seems undocumented as far as I can tell, that might be a misconception on my part.
There is an influx-db client for Java, which I'll try next, but at the end of the day I don't want multiple components in my application doing the same thing just because I'm not familiar with the tools I inherited.
InfluxMeterRegistry is a StepMeterRegistry, so the created Counter from it is a StepCounter. StepCounter.increment() increments the count in the current step but StepCounter.count() will return the count in the previous step. That's why you're seeing 0 with count() although you've already invoked increment() several times. You can see it in the next step and the default step is 1 minute, so you have to wait for 1 minute to see it.
See the following test to get an idea on how it works: https://github.com/izeye/sample-micrometer-spring-boot/blob/influx/src/test/java/com/izeye/sample/InfluxMeterRegistryTests.java

Spring + Hibernate: Query Plan Cache Memory usage

I'm programming an application with the latest version of Spring Boot. I recently became problems with growing heap, that can not be garbage collected. The analysis of the heap with Eclipse MAT showed that, within one hour of running the application, the heap grew to 630MB and with Hibernate's SessionFactoryImpl using more than 75% of the whole heap.
Is was looking for possible sources around the Query Plan Cache, but the only thing I found was this, but that did not play out. The properties were set like this:
spring.jpa.properties.hibernate.query.plan_cache_max_soft_references=1024
spring.jpa.properties.hibernate.query.plan_cache_max_strong_references=64
The database queries are all generated by the Spring's Query magic, using repository interfaces like in this documentation. There are about 20 different queries generated with this technique. No other native SQL or HQL are used.
Sample:
#Transactional
public interface TrendingTopicRepository extends JpaRepository<TrendingTopic, Integer> {
List<TrendingTopic> findByNameAndSource(String name, String source);
List<TrendingTopic> findByDateBetween(Date dateStart, Date dateEnd);
Long countByDateBetweenAndName(Date dateStart, Date dateEnd, String name);
}
or
List<SomeObject> findByNameAndUrlIn(String name, Collection<String> urls);
as example for IN usage.
Question is: Why does the query plan cache keep growing (it does not stop, it ends in a full heap) and how to prevent this? Did anyone encounter a similar problem?
Versions:
Spring Boot 1.2.5
Hibernate 4.3.10
I've hit this issue as well. It basically boils down to having variable number of values in your IN clause and Hibernate trying to cache those query plans.
There are two great blog posts on this topic.
The first:
Using Hibernate 4.2 and MySQL in a project with an in-clause query
such as: select t from Thing t where t.id in (?)
Hibernate caches these parsed HQL queries. Specifically the Hibernate
SessionFactoryImpl has QueryPlanCache with queryPlanCache and
parameterMetadataCache. But this proved to be a problem when the
number of parameters for the in-clause is large and varies.
These caches grow for every distinct query. So this query with 6000
parameters is not the same as 6001.
The in-clause query is expanded to the number of parameters in the
collection. Metadata is included in the query plan for each parameter
in the query, including a generated name like x10_, x11_ , etc.
Imagine 4000 different variations in the number of in-clause parameter
counts, each of these with an average of 4000 parameters. The query
metadata for each parameter quickly adds up in memory, filling up the
heap, since it can't be garbage collected.
This continues until all different variations in the query parameter
count is cached or the JVM runs out of heap memory and starts throwing
java.lang.OutOfMemoryError: Java heap space.
Avoiding in-clauses is an option, as well as using a fixed collection
size for the parameter (or at least a smaller size).
For configuring the query plan cache max size, see the property
hibernate.query.plan_cache_max_size, defaulting to 2048 (easily too
large for queries with many parameters).
And second (also referenced from the first):
Hibernate internally uses a cache that maps HQL statements (as
strings) to query plans. The cache consists of a bounded map limited
by default to 2048 elements (configurable). All HQL queries are loaded
through this cache. In case of a miss, the entry is automatically
added to the cache. This makes it very susceptible to thrashing - a
scenario in which we constantly put new entries into the cache without
ever reusing them and thus preventing the cache from bringing any
performance gains (it even adds some cache management overhead). To
make things worse, it is hard to detect this situation by chance - you
have to explicitly profile the cache in order to notice that you have
a problem there. I will say a few words on how this could be done
later on.
So the cache thrashing results from new queries being generated at
high rates. This can be caused by a multitude of issues. The two most
common that I have seen are - bugs in hibernate which cause parameters
to be rendered in the JPQL statement instead of being passed as
parameters and the use of an "in" - clause.
Due to some obscure bugs in hibernate, there are situations when
parameters are not handled correctly and are rendered into the JPQL
query (as an example check out HHH-6280). If you have a query that is
affected by such defects and it is executed at high rates, it will
thrash your query plan cache because each JPQL query generated is
almost unique (containing IDs of your entities for example).
The second issue lays in the way that hibernate processes queries with
an "in" clause (e.g. give me all person entities whose company id
field is one of 1, 2, 10, 18). For each distinct number of parameters
in the "in"-clause, hibernate will produce a different query - e.g.
select x from Person x where x.company.id in (:id0_) for 1 parameter,
select x from Person x where x.company.id in (:id0_, :id1_) for 2
parameters and so on. All these queries are considered different, as
far as the query plan cache is concerned, resulting again in cache
thrashing. You could probably work around this issue by writing a
utility class to produce only certain number of parameters - e.g. 1,
10, 100, 200, 500, 1000. If you, for example, pass 22 parameters, it
will return a list of 100 elements with the 22 parameters included in
it and the remaining 78 parameters set to an impossible value (e.g. -1
for IDs used for foreign keys). I agree that this is an ugly hack but
could get the job done. As a result you will only have at most 6
unique queries in your cache and thus reduce thrashing.
So how do you find out that you have the issue? You could write some
additional code and expose metrics with the number of entries in the
cache e.g. over JMX, tune logging and analyze the logs, etc. If you do
not want to (or can not) modify the application, you could just dump
the heap and run this OQL query against it (e.g. using mat): SELECT l.query.toString() FROM INSTANCEOF org.hibernate.engine.query.spi.QueryPlanCache$HQLQueryPlanKey l. It
will output all queries currently located in any query plan cache on
your heap. It should be pretty easy to spot whether you are affected
by any of the aforementioned problems.
As far as the performance impact goes, it is hard to say as it depends
on too many factors. I have seen a very trivial query causing 10-20 ms
of overhead spent in creating a new HQL query plan. In general, if
there is a cache somewhere, there must be a good reason for that - a
miss is probably expensive so your should try to avoid misses as much
as possible. Last but not least, your database will have to handle
large amounts of unique SQL statements too - causing it to parse them
and maybe create different execution plans for every one of them.
I have same problems with many(>10000) parameters in IN-queries. The number of my parameters is always different and I can not predict this, my QueryCachePlan growing too fast.
For database systems supporting execution plan caching, there's a better chance of hitting the cache if the number of possible IN clause parameters lowers.
Fortunately Hibernate of version 5.2.18 and higher has a solution with padding of parameters in IN-clause.
Hibernate can expand the bind parameters to power-of-two: 4, 8, 16, 32, 64.
This way, an IN clause with 5, 6, or 7 bind parameters will use the 8 IN clause, therefore reusing its execution plan.
If you want to activate this feature, you need to set this property to true hibernate.query.in_clause_parameter_padding=true.
For more information see this article, atlassian.
I had the exact same problem using Spring Boot 1.5.7 with Spring Data (Hibernate) and the following config solved the problem (memory leak):
spring:
jpa:
properties:
hibernate:
query:
plan_cache_max_size: 64
plan_parameter_metadata_max_size: 32
Starting with Hibernate 5.2.12, you can specify a hibernate configuration property to change how literals are to be bound to the underlying JDBC prepared statements by using the following:
hibernate.criteria.literal_handling_mode=BIND
From the Java documentation, this configuration property has 3 settings
AUTO (default)
BIND - Increases the likelihood of jdbc statement caching using bind parameters.
INLINE - Inlines the values rather than using parameters (be careful of SQL injection).
I had a similar issue, the issue is because you are creating the query and not using the PreparedStatement. So what happens here is for each query with different parameters it creates an execution plan and caches it.
If you use a prepared statement then you should see a major improvement in the memory being used.
TL;DR: Try to replace the IN() queries with ANY() or eliminate them
Explanation:
If a query contains IN(...) then a plan is created for each amount of values inside IN(...), since the query is different each time.
So if you have IN('a','b','c') and IN ('a','b','c','d','e') - those are two different query strings/plans to cache. This answer tells more about it.
In case of ANY(...) a single (array) parameter can be passed, so the query string will remain the same and the prepared statement plan will be cached once (example given below).
Cause:
This line might cause the issue:
List<SomeObject> findByNameAndUrlIn(String name, Collection<String> urls);
as under the hood it generates different IN() queries for every amount of values in "urls" collection.
Warning:
You may have IN() query without writing it and even without knowing about it.
ORM's such as Hibernate may generate them in the background - sometimes in unexpected places and sometimes in a non-optimal ways.
So consider enabling query logs to see the actual queries you have.
Fix:
Here is a (pseudo)code that may fix issue:
query = "SELECT * FROM trending_topic t WHERE t.name=? AND t.url=?"
PreparedStatement preparedStatement = connection.prepareStatement(queryTemplate);
currentPreparedStatement.setString(1, name); // safely replace first query parameter with name
currentPreparedStatement.setArray(2, connection.createArrayOf("text", urls.toArray())); // replace 2nd parameter with array of texts, like "=ANY(ARRAY['aaa','bbb'])"
But:
Don't take any solution as a ready-to-use answer. Make sure to test the final performance on actual/big data before going to production - no matter which answer you choose.
Why? Because IN and ANY both have pros and cons, and they can bring serious performance issues if used improperly (see examples in references below). Also make sure to use parameter binding to avoid security issues as well.
References:
100x faster Postgres performance by changing 1 line - performance of Any(ARRAY[]) vs ANY(VALUES())
Index not used with =any() but used with in - different performance of IN and ANY
Understanding SQL Server query plan cache
Hope this helps. Make sure to leave a feedback whether it worked or not - in order to help people like you. Thanks!
I had a big issue with this queryPlanCache, so I did a Hibernate cache monitor to see the queries in the queryPlanCache.
I am using in QA environment as a Spring task each 5 minutes.
I found which IN queries I had to change to solve my cache problem.
A detail is: I am using Hibernate 4.2.18 and I don't know if will be useful with other versions.
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.dao.GenericDAO;
public class CacheMonitor {
private final Logger logger = LoggerFactory.getLogger(getClass());
#PersistenceContext(unitName = "MyPU")
private void setEntityManager(EntityManager entityManager) {
HibernateEntityManagerFactory hemf = (HibernateEntityManagerFactory) entityManager.getEntityManagerFactory();
sessionFactory = (SessionFactoryImpl) hemf.getSessionFactory();
fillQueryMaps();
}
private SessionFactoryImpl sessionFactory;
private BoundedConcurrentHashMap queryPlanCache;
private BoundedConcurrentHashMap parameterMetadataCache;
/*
* I tried to use a MAP and use compare compareToIgnoreCase.
* But remember this is causing memory leak. Doing this
* you will explode the memory faster that it already was.
*/
public void log() {
if (!logger.isDebugEnabled()) {
return;
}
if (queryPlanCache != null) {
long cacheSize = queryPlanCache.size();
logger.debug(String.format("QueryPlanCache size is :%s ", Long.toString(cacheSize)));
for (Object key : queryPlanCache.keySet()) {
int filterKeysSize = 0;
// QueryPlanCache.HQLQueryPlanKey (Inner Class)
Object queryValue = getValueByField(key, "query", false);
if (queryValue == null) {
// NativeSQLQuerySpecification
queryValue = getValueByField(key, "queryString");
filterKeysSize = ((Set) getValueByField(key, "querySpaces")).size();
if (queryValue != null) {
writeLog(queryValue, filterKeysSize, false);
}
} else {
filterKeysSize = ((Set) getValueByField(key, "filterKeys")).size();
writeLog(queryValue, filterKeysSize, true);
}
}
}
if (parameterMetadataCache != null) {
long cacheSize = parameterMetadataCache.size();
logger.debug(String.format("ParameterMetadataCache size is :%s ", Long.toString(cacheSize)));
for (Object key : parameterMetadataCache.keySet()) {
logger.debug("Query:{}", key);
}
}
}
private void writeLog(Object query, Integer size, boolean b) {
if (query == null || query.toString().trim().isEmpty()) {
return;
}
StringBuilder builder = new StringBuilder();
builder.append(b == true ? "JPQL " : "NATIVE ");
builder.append("filterKeysSize").append(":").append(size);
builder.append("\n").append(query).append("\n");
logger.debug(builder.toString());
}
private void fillQueryMaps() {
Field queryPlanCacheSessionField = null;
Field queryPlanCacheField = null;
Field parameterMetadataCacheField = null;
try {
queryPlanCacheSessionField = searchField(sessionFactory.getClass(), "queryPlanCache");
queryPlanCacheSessionField.setAccessible(true);
queryPlanCacheField = searchField(queryPlanCacheSessionField.get(sessionFactory).getClass(), "queryPlanCache");
queryPlanCacheField.setAccessible(true);
parameterMetadataCacheField = searchField(queryPlanCacheSessionField.get(sessionFactory).getClass(), "parameterMetadataCache");
parameterMetadataCacheField.setAccessible(true);
queryPlanCache = (BoundedConcurrentHashMap) queryPlanCacheField.get(queryPlanCacheSessionField.get(sessionFactory));
parameterMetadataCache = (BoundedConcurrentHashMap) parameterMetadataCacheField.get(queryPlanCacheSessionField.get(sessionFactory));
} catch (Exception e) {
logger.error("Failed fillQueryMaps", e);
} finally {
queryPlanCacheSessionField.setAccessible(false);
queryPlanCacheField.setAccessible(false);
parameterMetadataCacheField.setAccessible(false);
}
}
private <T> T getValueByField(Object toBeSearched, String fieldName) {
return getValueByField(toBeSearched, fieldName, true);
}
#SuppressWarnings("unchecked")
private <T> T getValueByField(Object toBeSearched, String fieldName, boolean logErro) {
Boolean accessible = null;
Field f = null;
try {
f = searchField(toBeSearched.getClass(), fieldName, logErro);
accessible = f.isAccessible();
f.setAccessible(true);
return (T) f.get(toBeSearched);
} catch (Exception e) {
if (logErro) {
logger.error("Field: {} error trying to get for: {}", fieldName, toBeSearched.getClass().getName());
}
return null;
} finally {
if (accessible != null) {
f.setAccessible(accessible);
}
}
}
private Field searchField(Class<?> type, String fieldName) {
return searchField(type, fieldName, true);
}
private Field searchField(Class<?> type, String fieldName, boolean log) {
List<Field> fields = new ArrayList<Field>();
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
fields.addAll(Arrays.asList(c.getDeclaredFields()));
for (Field f : c.getDeclaredFields()) {
if (fieldName.equals(f.getName())) {
return f;
}
}
}
if (log) {
logger.warn("Field: {} not found for type: {}", fieldName, type.getName());
}
return null;
}
}
We also had a QueryPlanCache with growing heap usage. We had IN-queries which we rewrote, and additionally we have queries which use custom types. Turned out that the Hibernate class CustomType didn't properly implement equals and hashCode thereby creating a new key for every query instance. This is now solved in Hibernate 5.3.
See https://hibernate.atlassian.net/browse/HHH-12463.
You still need to properly implement equals/hashCode in your userTypes to make it work properly.
We had faced this issue with query plan cache growing too fast and old gen heap was also growing along with it as gc was unable to collect it.The culprit was JPA query taking some more than 200000 ids in the IN clause. To optimise the query we used joins instead of fetching ids from one table and passing those in other table select query..

How to benchmark single TypoSript Object generation?

I would like to benchmark single TypoScript object generation to control the performance, is it possible, probably, with some stdWrap methods ?
Example of TS objects, which I would like to benchmark :
Test 1
page.10 = RECORDS
page.10 {
tables = pages
source = 1
dontCheckPid = 1
conf.pages = TEXT
conf.pages.field = title
}
Test 2
page.20 = CONTENT
page.20 {
table = tt_content
select {
pidInList = 0
recursive = 99
where = uid = 1
}
}
I need each object generation time and quantity of fired queries.
I guess it could be done via Extension. I guess there is a possibility to hook in (or xclass) the Database Layer (like DBAL does). In your extension you could then just test the different TypoScript setups via $this->cObj->cObjGetSingle($this->conf['test1'],$this->conf['test1.'],'test1');
Perhaps have a look at t3lib_timeTrack, may be it is enough what is tracked there. But AFAIK everything which is tracked is available via Admin-Panel (check all checkboxes).

Resources