To start, I understand what the "GC Overhead limit" error means, in general. I received this message while running a script that does the following:
Create Instance of an object that makes a CFHTTP GET request to an external API
Store JSON response (an array) as a property of the object Instance (i.e. VARIABLES.data)
Loop through the JSON response array using a for in loop
Create an instance on an object that calls a SQL Server Stored Procedure passing in the properties of the JSON object (the SQL Stored Procedure performs and UPDATE or INSERT based on the existence of a record for the object's key)
Debug output shows that the SP call takes between 3-12 milliseconds.
When I run this script with a limited dataset (~3,000 records), it runs to completion without throwing a GC exception.
When I run the script with the complete dataset (~14,000 records), the GC exception is thrown.
Here's my pseudo-code:
for (LOCAL.WidgetJson in VARIABLES.data) {
LOCAL.Widget=new Widget();
LOCAL.Widget
.save(argumentCollection=LOCAL.WidgetJson);
}
Widget.cfc:
private void function saveStoredProc() {
cfstoredproc(procedure="SaveWidget") {
cfprocparam(
dbvarname="#id",
type="in",
cfsqltype="CF_SQL_INT",
value=VARIABLES.id
);
<!--- Rest of cfprocparam() tags here --->
}
private void function save() {
for (LOCAL.Property in ARGUMENTS) {
if (StructKeyExists(ARGUMENTS, LOCAL.Property)) {
if (IsSimpleValue(ARGUMENTS[LOCAL.Property])) {
VARIABLES[LOCAL.Property] = Trim(ARGUMENTS[LOCAL.Property]);
}
else {
VARIABLES[LOCAL.Property] = ARGUMENTS[LOCAL.Property];
}
}
}
saveStoredProc();
}
I'm wondering if the way that I'm creating objects or looping could be improved to prevent GC exceptions/memory leaks.
Any ideas for improvements?
I don't think the garbage collection will happen during a single request even if it is necessary. You could either increase memory or split this into multiple threads that process smaller amounts of data.
Related
I implement a Dashboard functionality that checks every time at program start a list of Requirement-Objects for a bunch of different characteristics like progress, missing data and alike and sets for each characteristic a dedicated beacon on the UI.
protected void initializePerformanceIndicator() {
try {
updateA();
updateB();
...
updateF();
updateG();
} catch (Exception e) {
ErrorHandler.showError("Cannot show KPI Performance", e);
}
}
The checks have different compute demands some are faster some slower, therefore each of this checks runs in a dedicated Task to provide some feedback to the user. The skeleton of such a Task is always the same
protected void updateA() throws Exception {
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
embeddedBudgetKPIController.setHyperlink("Budget", null);
embeddedBudgetKPIController.setToolTip("...");
ObservableList<UserRequirement> issues = FXCollections.observableArrayList();
List<UserRequirement> requirements = reqService.getAllUserRequirements(false); // all requirements of the selected product
for(UserRequirement req: requirements) {
if(*some criteria*) {
issues.add(req);
}
}
if(issues.isEmpty()) {
embeddedBudgetKPIController.setBeaconColor(Color.GREEN);
} else {
embeddedBudgetKPIController.setBeaconColor(Color.RED);
}
return null;
};
};
task.setOnSucceeded(e -> {
// Nothing to do
});
Thread tt = new Thread(task);
tt.start();
}
Before initializePerformanceIndicator is called, I retrieved already elsewhere the data from the database querying a number Spring Repositories:
protected final ObservableList<UserRequirement> allUserRequirements = FXCollections.observableArrayList();
public synchronized ObservableList<UserRequirement> getAllUserRequirements(boolean forceUpdate) throws Exception {
logger.debug(""); // show that this method is called
Product selectedProduct = SelectedScope.getSelectedProduct();
if(selectedProduct == null) {
throw new Exception("No selProduct selected");
}
if(forceUpdate || allUserRequirements.isEmpty()) {
allUserRequirements.clear();
allUserRequirements.addAll(epicRepository.findByProductAndRevisionSuccessorIsNull(selectedProduct));
allUserRequirements.addAll(themeRepository.findByProductAndRevisionSuccessorIsNull(selectedProduct));
allUserRequirements.addAll(userStoryRepository.findByProductAndRevisionSuccessorIsNull(selectedProduct));
allUserRequirements.addAll(tangibleRepository.findByProductAndRevisionSuccessorIsNull(selectedProduct));
}
return allUserRequirements;
}
and as you see updateBudgetKPIController calls getallUserRequirements with the parameter false. Therefore it returns the buffered result set and is not re-fetching data from database. So far everything is fine.
I can run each of these Tasks individually without problem. I tried a number combinations with 2 Tasks. Works fine, but the program will never show more than three or four beacons. Which ones are shown differs as well - what is expected as a consequence of the different Tasks. If I exceed three or four Tasks I often get no error at all, but the UI is just not showing more than three to four beacons.
Sometimes I do get an error message, which is
WARN 08:14 o.h.e.j.s.SqlExceptionHelper.logExceptions:137: SQL Error: 0, SQLState: S1009
ERROR 08:14 o.h.e.j.s.SqlExceptionHelper.logExceptions:142: No operations allowed after statement closed.
I debugged it, and realized that I was generating way too many select statements. The UserRequirement entity has almost a dozen OneToMany relations, some where defined with FetchType.LAZY, so I thought it would be better anyway to configure all these relations as
#OneToMany(fetch = FetchType.LAZY, mappedBy="parent", cascade = CascadeType.ALL)
Because of the LAZY loading, every Task tries to load additional data in the if(*some criteria*) part.
The problem did not disappear but I get more information, as the error is now
WARN 11:02 o.h.c.i.AbstractPersistentCollection.withTemporarySessionIfNeeded:278: Unable to close temporary session used to load lazy collection associated to no session
WARN 11:02 o.h.e.j.s.SqlExceptionHelper.logExceptions:137: SQL Error: 0, SQLState: S1009
ERROR 11:02 o.h.e.j.s.SqlExceptionHelper.logExceptions:142: No operations allowed after statement closed.
So I do have a LAZY loading issue.
I am using Spring Boot 2.1.6, MySQL 8.0.15 Community Server, Hibernate Core {5.3.10.Final}, Java 1.8.0_211 and the com.mysql.cj.jdbc.Driver
From a former issue, I have in my properties file the following configuration
# Prevent LazyInitializationException
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
Don't know whether this has a side effect?!
Probably changing the LAZY loading to EAGER will fix it - haven't tried yet - but it would delay program start significantly. Therefore I would prefer a solution with LAZY loading.
Any ideas? I also appreciate any ideas regarding how to further isolate the root cause as the error message is not really explicit and I can't see which part of my code triggers it. Plus when I debug it, the behavior changes as I compute all Tasks sequentially rather then in parallel. Thank you in advance.
The issue was caused by different Tasks accessing the same getter of some of the entities. If the first getter call opened a connection, the second call got on it, and then the first call closed the ResultSet, the second call one was in trouble. Synchronizing the getter method solved the problem.
In short, what I am trying solve is how to recover from certain database errors in a Grails application using Hibernate and continue on with the transaction skipping over the failed row updates that are part of a batch of changes.
The application uses Grails 2.3.11 but I have also tried with version 1.3.8 with similar failed results.
Basically there is a Grails service class that iterates over a list of imported records and attempts to update associated master records appropriately. In certain situations exceptions might occur during the domain.save(flush:true) call e.g. org.hibernate.exception.DataException thrown due to issues like (Data truncation: Data too long for column ...).
At this point I have tried:
Disabling transactions
Using domainObj.withTransaction() for each individual record
Trying various #Transactional annotations
Calling domain.clearErrors() and domain.discard() after catching the exception
Tried using a nested service with Transactional annotation with noRollbackFor as shown below
A number of other approaches but nothing I've tried has worked
Example code:
#Transactional
class UpdateService {
public updateBatch(Integer batchId) {
...
list.each { record ->
record.value = 123
try {
nestedService.saveDomain()
} catch (e) {
record.clearErrors()
record.discard()
}
}
batch.status = "POSTED"
batch.save()
}
}
#Transactional
class NestedService {
#Transactional(propagation = Propagation.REQUIRED, noRollbackFor = RuntimeException.class)
public void saveDomain(domainObj) throws RuntimeException {
if (domainObj.validate() && domainObj.save(flush:true) {
log.info "domain $domain was saved"
}
}
}
Once an error occurs I can't seem to clear out the hibernate session. On each subsequent record being updated I receive the error:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction
where it indicates the original failed domain id.
Revision:
Vahid, Thanks for the suggestions. I have tried that. I realized one issue is that I am passing objects across transactional boundaries. So I experimented with the NestedService class do something along the lines of:
#Transactional(propagation = Propagation.REQUIRE_NEW)
public void saveDomain(domainObj) {
def newObj = new Domain.get(domainObj.id)
newObj.properties = domainObj.properties
if (newObj.validate() && newObj.save(force:true) ) { ... }
I expected that to work but the original domainObj still fails even though I'm not calling the save on it. Very strange...
A simple approach would be to loop and then use validate(). If it does fail, then just store the id of the failed entity and proceed.
if(!domainObject.validate()){
// store Id for trying it again later ?
}else{
// Save
}
I'm currently working on a project using AIR and Flex that uses a remote data source to persist data locally in a SQLite database. Currently, there's a lot of copy and paste code that I was trying to alleviate, so since we already use a DAO pattern with several common queries that get passed to it and a type that creates SQLStatement values, I figured I would simplify our codebase even more.
I applied the Adapter pattern to allow a wider range of possible database operations to be performed ([saveOrUpdate, find, findAll, remove] => [selectSingle, selectMultiple, insert, updateSingle, updateMultiple, deleteSingle, deleteMultiple]). I also applied the Strategy pattern to two aspects of the statement runner: the first time for what sort of aggregated type to return (either an Array of records or an ArrayCollection of records) for the selectMultiple function; the second time for creating or not creating historical records (ChangeObjects).
After applying these patterns and testing some refactored code, it worked perfectly with an existing SQLite database. I neglected to test its compatibility with the remote data source, since the saving mechanisms are used during that process as well. After refactoring and simplifying our code and nearing the end of the development cycle, I tested the download.
It would read data from the SQLite database, despite the fact that there was actually no data in it according to sqlite3.
I will give the related piece of code for this.
public class BaseDaoAdaptee {
private var returnStrategy: ReturnTypeStrategy;
private var trackingStrategy: TrackingStrategy;
private var creator: StatementCreator;
public function insert(queryTitle: String,
object: DaoAwareDTO,
parameters: Array,
mutator: Function,
handler: Function): void {
var statement: SQLStatement;
mutator = creator.validEmptyFunction(mutator);
handler = creator.validFault(handler);
statement = defaultStatement(queryTitle, parameters, handler);
statement.addEventListener(SQLEvent.RESULT,
trackingStrategy.onInserted(object, mutator), false, 0, true);
statement.execute();
}
}
The code for the TrackingStrategy implemented:
public class TrackedStrategy
implements TrackingStrategy {
public function onInserted(object: DaoAwareDTO,
callback: Function): Function {
return function (event: SQLEvent): void {
var change: Change,
id:Number = event.target.getResult().lastInsertRowID;
creator.logger.debug((event.target as SQLStatement).itemClass + ' (id # ' + id + ') inserted');
(object as Storeable).id = id;
change = new Creation(object);
change.register();
callback();
};
}
}
The logger reads that various database records were inserted, and when stopped on a breakpoint in the above lambda, "object" has all proper values. When running a Select statement in sqlite3, no records ever get returned.
Why would this happen?
Turns out an open transaction on a SQLConnection value was the cause. Got to love team projects. Commit or rollback your SQLConnection transactions!
I am trying to serve up my user repository via zend_json_server. The problem is the service is returning empty objects. What have i missed?
server side:
$repo = App_User_Repository::getInstance();
$server = new Zend_Json_Server();
$server->setClass($repo);
if ('GET' == $_SERVER['REQUEST_METHOD']) {
$server->setTarget('/service/json-rpc.php')
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$smd = $server->getServiceMap();
// Set Dojo compatibility:
$smd->setDojoCompatible(true);
header('Content-Type: application/json');
echo $smd;
return;
}
$server->handle();
client side:
var object = new dojo.rpc.JsonService('/service/json-rpc.php');
var deferred = object.getById(1);
deferred.addBoth(function(result) {console.log(result)});
Firebug console output:
Object {}
This should be a User object
When doing the actual RPC with the "getById()" method, an dojo.deferred object is returned. At this point, a asynchronous request is running. By using the deferred object, you can define callbacks and error handlers in advance whilst waiting for the response to be returned.
Check if the actual response object isn't empty as well. Remember, you still have to use the return keyword in your attached classes to return results back to Zend_Json_Server. Zend_Json_Server will then serialize and send back the returned value automatically. A response from Zend_Json_Server is always a serialized object in JSON, containing an id (which increments automatically with each request), an string indicating what jsonrpc version is being used (ie. 2.0) and of course a result containing the returned data from the attached class.
The setClass() method should not be a object instance, but a string containing the className of the class you want to attach. Zend_Json_Server handles the creation of the object instance by itself, as well as generating the SMD (Service Method/Mapper Description). Remember to document each public method with docblocks, as Zend_Json_Server uses those docblocks to determine the SMD.
Furthermore, it is much more handy to use a fluent-like interface with the then() method like so:
var myService = new dojo.rpc.JsonService('/service/json-rpc.php?');
var deferredObj = myService.doThis('myArgument');
deferredObj.then(callback, errorHandler).then(afterCallback).then(cleanUp);
In above example, the variables callback, errorHandler, afterCallback and cleanUp, are actually references to functions. The first then() method you call, automatically passes the rpc result to the callback function. If you throw an exception from within the attached rpc class, the errorHandler method (second optional argument of the first then() method call) will be called instead.
More information: http://www.sitepen.com/blog/2010/05/03/robust-promises-with-dojo-deferred-1-5/
I recently ran into the same problem and it wasn't a problem with dojo deferred. I'm assuming getById(1) is your remote function call, in which case if your server finds results dojo shouldn't get the empty object. Even using addBoth method on a deferred object would still show the result from the server, which leads me to believe your problem is not in any of the code you've listed, but getById(1) call in your App_User_Repository class. Did you use Zend_Dojo_Data or something else to json encode before returning? That would clobber your result, Zend_Json_Server does the encoding for you.
I have implemented a DAL using Rob Conery's spin on the repository pattern (from the MVC Storefront project) where I map database objects to domain objects using Linq and use Linq to SQL to actually get the data.
This is all working wonderfully giving me the full control over the shape of my domain objects that I want, but I have hit a problem with concurrency that I thought I'd ask about here. I have concurrency working but the solution feels like it might be wrong (just one of those gitchy feelings).
The basic pattern is:
private MyDataContext _datacontext
private Table _tasks;
public Repository(MyDataContext datacontext)
{
_dataContext = datacontext;
}
public void GetTasks()
{
_tasks = from t in _dataContext.Tasks;
return from t in _tasks
select new Domain.Task
{
Name = t.Name,
Id = t.TaskId,
Description = t.Description
};
}
public void SaveTask(Domain.Task task)
{
Task dbTask = null;
// Logic for new tasks omitted...
dbTask = (from t in _tasks
where t.TaskId == task.Id
select t).SingleOrDefault();
dbTask.Description = task.Description,
dbTask.Name = task.Name,
_dataContext.SubmitChanges();
}
So with that implementation I've lost concurrency tracking because of the mapping to the domain task. I get it back by storing the private Table which is my datacontext list of tasks at the time of getting the original task.
I then update the tasks from this stored Table and save what I've updated
This is working - I get change conflict exceptions raised when there are concurrency violations, just as I want.
However, it just screams to me that I've missed a trick.
Is there a better way of doing this?
I've looked at the .Attach method on the datacontext but that appears to require storing the original version in a similar way to what I'm already doing.
I also know that I could avoid all this by doing away with the domain objects and letting the Linq to SQL generated objects all the way up my stack - but I dislike that just as much as I dislike the way I'm handling concurrency.
I worked through this and found the following solution. It works in all the test cases I (and more importantly, my testers!) can think of.
I am using the .Attach() method on the datacontext, and a TimeStamp column. This works fine for the first time that you save a particular primary key back to the database but I found that the datacontext throws a System.Data.Linq.DuplicateKeyException "Cannot add an entity with a key that is already in use."
The work around for this I created was to add a dictionary that stored the item I attach the first time around and then every subsequent time I save I reuse that item.
Example code is below, I do wonder if I've missed any tricks - concurrency is pretty fundamental so the hoops I'm jumping through seem a little excessive.
Hopefully the below proves useful, or someone can point me towards a better implementation!
private Dictionary<int, Payment> _attachedPayments;
public void SavePayments(IList<Domain.Payment> payments)
{
Dictionary<Payment, Domain.Payment> savedPayments =
new Dictionary<Payment, Domain.Payment>();
// Items with a zero id are new
foreach (Domain.Payment p in payments.Where(p => p.PaymentId != 0))
{
// The list of attached payments that works around the linq datacontext
// duplicatekey exception
if (_attachedPayments.ContainsKey(p.PaymentId)) // Already attached
{
Payment dbPayment = _attachedPayments[p.PaymentId];
// Just a method that maps domain to datacontext types
MapDomainPaymentToDBPayment(p, dbPayment, false);
savedPayments.Add(dbPayment, p);
}
else // Attach this payment to the datacontext
{
Payment dbPayment = new Payment();
MapDomainPaymentToDBPayment(p, dbPayment, true);
_dataContext.Payments.Attach(dbPayment, true);
savedPayments.Add(dbPayment, p);
}
}
// There is some code snipped but this is just brand new payments
foreach (var payment in newPayments)
{
Domain.Payment payment1 = payment;
Payment newPayment = new Payment();
MapDomainPaymentToDBPayment(payment1, newPayment, false);
_dataContext.Payments.InsertOnSubmit(newPayment);
savedPayments.Add(newPayment, payment);
}
try
{
_dataContext.SubmitChanges();
// Grab the Timestamp into the domain object
foreach (Payment p in savedPayments.Keys)
{
savedPayments[p].PaymentId = p.PaymentId;
savedPayments[p].Timestamp = p.Timestamp;
_attachedPayments[savedPayments[p].PaymentId] = p;
}
}
catch (ChangeConflictException ex)
{
foreach (ObjectChangeConflict occ in _dataContext.ChangeConflicts)
{
Payment entityInConflict = (Payment) occ.Object;
// Use the datacontext refresh so that I can display the new values
_dataContext.Refresh(RefreshMode.OverwriteCurrentValues, entityInConflict);
_attachedPayments[entityInConflict.PaymentId] = entityInConflict;
}
throw;
}
}
I would look at trying to utilise the .Attach method by passing the 'original' and 'updated' objects thus achieving true optimistic concurrency checking from LINQ2SQL. This IMO would be preferred to using version or datetime stamps either in the DBML objects or your Domain objects. I'm not sure how MVC allows for this idea of persisting the 'original' data however.. i've been trying to investigate the validation scaffolding in the hope that it's storing the 'original' data.. but i suspect that it is as only as good as the most recent post (and/or failed validation). So that idea may not work.
Another crazy idea i had was this: override the GetHashCode() for all of your domain objects where the hash represents the unique set of data for that object (minus the ID of course). Then, either manually or with a helper bury that hash in a hidden field in the HTML POST form and send it back to your service layer with your updated domain object - do the concurrency checking in your service layer or data layer (by comparing the original hash with a newly extracted domain object's hash) but be aware that you need to be checking for and raising concurrency exceptions yourself. It's nice to use the DMBL functions but the idea of abstracting away the data layer is so to not depend on the particular implementation's features etc. So having full control of the optimistic concurrency checking on your domain objects in your service layer (for example) seems like a good approach to me.