Accessing global variable in multithreaded Tomcat server - linux

Edit: I've figured out the constructor for the singleton is getting called multiple times so it appears the classes are getting loaded more than once by separate class loaders. How can I make a global singleton in Tomcat? I've been googling, but no luck so far.
I have a singleton object that I construct like thus:
private static volatile KeyMapper mapper = null;
public static KeyMapper getMapper()
{
if(mapper == null)
{
synchronized(Utils.class)
{
if(mapper == null)
{
mapper = new LocalMemoryMapper();
}
}
}
return mapper;
}
The class KeyMapper is basically a synchronized wrapper to HashMap with only two functions, one to add a mapping and one to remove a mapping. When running in Tomcat 6.24 on my 32bit Windows machine everything works fine. However when running on a 64 bit Linux machine (CentOS 5.4 with OpenJDK 1.6.0-b09) I add one mapping and print out the size of the HashMap used by KeyMapper to verify the mapping got added (i.e. verify size = 1). Then I try to retrieve the mapping with another request and I keep getting null and when I checked the size of the HashMap it was 0. I'm confident the mapping isn't accidentally being removed since I've commented out all calls to remove (and I don't use clear or any other mutators, just get and put).
The requests are going through Tomcat 6.24 (configured to use 200 threads with a minimum of 4 threads) and I passed -Xnoclassgc to the jvm to ensure the class isn't inadvertently getting garbage collected (jvm is also running in -server mode). I also added a finalize method to KeyMapper to print to stderr if it ever gets garbage collected to verify that it wasn't being garbage collected.
I'm at my wits end and I can't figure out why one minute the entry in HashMap is there and the next it isn't :(

Another wild guess: is it possible the two requests are being served by different copies of your web app? Each would be in its own ClassLoader and thus have a different copy of the singleton.

Have you tried removing the outer check
if(mapper == null)
{
Thereby always hitting the Synchronized point, it's subtle stuff but possibly you're hitting the double-checked locking idiom problem. Described here and in many other articles.
Must admit I've never seen the problem actually bite someone before, but this sure sounds like it.

With this solution, the JVM guarantees that it's only one mapper and that's it's initialized before use.
public enum KeyMapperFactory {
;
private static KeyMapper mapper = new LocalMemoryMapper();
public static KeyMapper getMapper() {
return mapper;
}
}

This may not be the cause of your problem but you are using the faulty double-checked locking. See this,
http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java

I found a rather poor fix. I exported my code as a JAR and put it in $TOMCAT/lib and that worked. This is clearly a class loader issue.
Edit: Figured out the solution
Ok, I finally figured out the problem.
I had made my application the default application for the server by adding a to server.xml and setting the path to "". However, when I was accessing it through the URL http://localhost/somepage.jsp for somethings, but also the URL http://localhost/appname/anotherpage.jsp for other things.
Once I changed all the URLs to use http://localhost/ instead of http://localhost/appname the problem was fixed.

Related

Why is InvocationInterceptor active in dev-mode?

Today, while profiling a Quarkus app, I found out that io.quarkus.arc.runtime.devconsole.InvocationInterceptor seems to intercept (almost?) all bean classes when Quarkus is running in dev mode, even though the Interceptor has an InterceptorBinding that is not used anywhere in the application code.
#Inherited
#InterceptorBinding
#Target({ TYPE, METHOD })
#Retention(RUNTIME)
public #interface Monitored {
}
#Priority(Interceptor.Priority.LIBRARY_BEFORE)
#Monitored
#Interceptor
public class InvocationInterceptor {
//...
}
Can somebody explain to me why that is the case? I can't really tell if this is intended behaviour or a bug. Is the InterceptorBinding automatically sprinkled around my app during the build? I looked through the code, but could not find a place where that happened.
Why am I interested in that? The bookkeeping this interceptor does uses a CopyOnWriteArrayList (inside Invocation.Builder) which, in a hot loop will quickly generate tens of thousands of copies of that list. Today, that confused the heck out of me while I was profiling the app, because the memory requirements were so drastically different between prod and dev mode.
(If relevant: All of this happened with Quarkus 2.7.3.Final)
This is essentially #Ladicek's comment:
[The behaviour] is intentional, but there are discussions it should be off by default. In any case, there's a configuration property to switch it off.
I was also able to locate the BuildExtension that does the magic: It is located inside io.quarkus.arc.deployment.devconsole.ArcDevConsoleProcessor.

Pagination and Sorting in cassandra using spring-data-cassandra

first of all, if any developper of the lib spring-data-cassandra read me : Thank you for your work, the lib is working like a charm and is well integrated to spring project.
Here is, a few days ago i was facing a problem when trying to use pagination in cassandra. I found a workaround to my problem and will explain how did i do that.
My problem is the following, i've been using pagination for cassandra and i've had to iterate over the slices of results and it worked until i decided to use Sort in pagination.
To achieve that i've used:
-a service using a Repository extending CassandraRepository
here is the code (the service wrapping the repository)
public Slice<Pony> getAllByTypePage(Pageable p, EnumType type) {
Slice<Pony> slice = ponyRepository.findAllByType(p.first(), type);
//Iterate over slices
while(slice.hasNext()&&slice.getPageable().getPageNumber()<p.getPageNumber())
{
slice = ponyRepository.findAllByType(slice.nextPageable(), type);
}
return slice;
}
Pony is my Model en ponyRepository is my CassandraReposity
#Repository
public interface PonyRepository extends CassandraRepository<Pony,UUID> {
#Async
CompletableFuture<Long> countByType(EnumType type);
Slice<Pony> findAllByType(Pageable p,EnumType type);
}
When i try to get a page (other than the first one) i get this exception
com.datastax.driver.core.exceptions.PagingStateException: Paging state mismatch, this means that either the paging state contents were altered, or you're trying to apply it to a different statement
after some debugging i've seen that the pageable object i obtained in the slice.nextPageable() was in Sort.UNSORTED mode instead of having the sort of my input pageable.
then, knowing that i made this workaround:
public Slice<Pony> getAllByTypePage(Pageable p, EnumType type) {
Slice<Pony> slice = ponyRepository.findAllByType(p.first(), type);
//using a sidePageable and incrementing it in parallel
Pageable sidePageable = p.first();
//Iterate over slices
while(slice.hasNext()&&sidePageable.getPageNumber()<p.getPageNumber())
{
CassandraPageRequest cpr = CassandraPageRequest.of(sidePageable.next(), ((CassandraPageRequest)slice.getPageable()).getPagingState());
slice = ponyRepository.findAllByType(cpr, type);
sidePageable=sidePageable.next();
}
return slice;
}
the workaround seems to work.
Is this behavior is normal or is it a bug?
i have not seen any issues about this in the jira (maybe i did not looked at the good place).
here is the related libs i use (spring boot 2.2.1/spring code 5.2.1):
spring-data-cassandra : 2.2.1.RELEASE
cassandra-driver-core: 3.7.2
i have seen the same behavior on spring core 5.1.5
Best Regards
like said in the previous comments, it was a bug.
this is already fixed (see the issue linked before).
I just tried with the snapshot 2.2.2.BUILD-20191113.121102-4 and it seems to work.
for now i'll use my workaround. When the lib will be released i'll upgrade.
thanks for the help #mp911de

Application Object Won't Share

I'm having issues with my Application Object. I am currently using a Service to simulate incoming data from an electronic game board. This data is represented as a 2D boolean array. Every five seconds the Service uses a method of the Application Object to update the array (setDetectionMap()). This array is being read by a Thread in my main Activity using another method (getDetectionMap()). After some debugging I am almost positive that the main Activity is not seeing the changes. Here is the code for my Application Object:
public class ChessApplication extends Application{
private static ChessApplication singleton;
private boolean[][] detectionMap;
public static ChessApplication getInstance(){
return singleton;
}
#Override
public void onCreate() {
super.onCreate();
singleton=this;
detectionMap=new boolean[8][8];
}
public boolean[][] getDetectionMap(){
return detectionMap;
}
public void setDetectionMap(boolean[][] newMap){
detectionMap=newMap;
Log.d("Chess Application","Board Changed");
}
}
I've checked my Manifest, I've rewritten my object declaration a dozen times, I've added LogCat tags to make sure that the code is executing when I think it should be, and I've even implemented the supposedly redundant Singleton code. Any ideas what could be causing this? Incidentally can anyone tell me how to view variable states as the activity is running? Thanks in advance.
Is your Activity calling getDetectionMap() to get the new map after the update occurs?
Because otherwise, it's holding onto a reference to the old boolean[][] array, wheras setDetectionMap(...) isn't actually updating the current data structure, it's just updating the "detectionMap" variable to point to a different one. As such, your main activity won't be aware of the swapout until the next time it calls getDetectionMap.
Easy fix: in setDetectionMap, manually copy values from newMap into detectionMap. Or, update the Activity's reference so it's looking at the right map.
One other observation entirely unrelated to the original question: It's quite unusual to override Application during Android development, and is usually considered a "code smell" unless you have a really good reason for doing so. In this case I imagine it's so that you can communicate between your service and Activity, but you create a middle-man where one isn't entirely necessary. Here's a useful SO thread on how to communicate directly between the two :)

NInject and thread-safety

I am having problems with the following class in a multi-threaded environment:
public class Foo
{
[Inject]
public IBar InjectedBar { get; set; }
public bool NonInjectedProp { get; set; }
public void DoSomething()
{
/* The following line is causing a null-reference exception */
InjectedBar.DoSomething();
}
public Foo(bool nonInjectedProp)
{
/* This line should inject the InjectedBar property */
KernelContainer.Inject(this);
NonInjectedProp = nonInjectedProp;
}
}
This is a legacy class which is why I am using property rather than constructor injection.
Sometime when the DoSomething() is called the InjectedBar property is null. In a single-threaded application, everything runs fine.
How can this be occuring and how can I prevent it?
I am using NInject 2.0 without any extensions, although I have copied the KernelContainer from the NInject.Web project.
I have noticed a similar problem occurring in my web services. This problem is extremely intermittent and difficult to replicate.
First of all, let me say that this is wrong on so many levels; the KernelContainer was an infrastructure class kept specifically to work around certain limitations in the ASP.NET WebForms page lifecycle. It was never meant to be used in application code. Using the Ninject kernel (or any DI container) as a service locator is an anti-pattern.
That being said, Ninject itself is definitely thread-safe because it's used to service parallel requests in ASP.NET all the time. Wherever this NullReferenceException is coming from, it's got little if anything to do with Ninject.
I can think of two possibilities:
You have to initialize KernelContainer.Kernel somewhere, and that code might have a race condition. If something tries to use the KernelContainer before the kernel is fully initialized (possible if you use the IKernel.Bind methods instead of loading modules as per the guidance), you'll get errors like this. Or:
It's your IBar implementation itself that has problems, and the NullReferenceException is happening somewhere inside the DoSomething method. You don't actually specify that InjectedBar is null when you get the exception, so that's a legitimate possibility here.
Just to narrow the field of possibilities, I'd eliminate the KernelContainer first. If you absolutely must use Ninject as a service locator due to a poorly-designed legacy architecture, then at least allow it to create the dependencies instead of relying on Inject(this). That is to say, whichever class or classes need to create your Foo, have that class call kernel.Get<Foo>(), and set up your kernel to Bind<Foo>().ToSelf().

trust set to Full, but web part still causes SecurityException

I've got a web part that accesses the SP object model, packaged in an assembly which is signed and deployed to the GAC. The web.config is set for "Full" trust, and yet my web part throws a SecurityException. The offending lines of code:
SPSecurity.RunWithElevatedPrivileges(new SPSecurity.CodeToRunElevated(() =>
{
foreach (SPGroup g in user.Groups)
{
identity += String.Format(",'{0}'", g.Name.ToLowerInvariant().Replace(#"\", #"\\"));
}
}));
It appears that the exception is thrown when RunWithElevatedPrivileges is called (in other words, my delegate doesn't execute at all). Any ideas? I'm completely bewildered at this point.
update: here's what the code looked like before I wrapped it in the RunWithElevatedPrivileges method:
public MyWebPart()
{
context = new MyProject.Data.MyDataContext(ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString);
SPUser user = SPContext.Current.Web.CurrentUser;
identity = String.Format("'{0}'", user.LoginName.ToLowerInvariant().Replace(#"\", #"\\"));
foreach (SPGroup g in user.Groups)
{
identity += String.Format(",'{0}'", g.Name.ToLowerInvariant().Replace(#"\", #"\\"));
}
identity = '[' + identity + ']';
}
And the exception:
System.Security.SecurityException occurred
Message="Request failed."
Source="Microsoft.SharePoint"
StackTrace:
at Microsoft.SharePoint.SPBaseCollection.System.Collections.IEnumerable.GetEnumerator()
at MyProject.MyWebPart..ctor()
InnerException:
Based on the highlight provided by the exception helper, it looks like the attempted access of the SPUser.Groups property is the problem: user.Groups.
What's got me really confused is that this exact code was working fine two days ago, but I had some other problems with the farm and basically had to rebuild it. After getting everything else back up again, I went and tried to add this web part to a page and this problem manifested itself. I tried wrapping the code in the RunWithElevatedPrivileges wrapper to see if I could isolate exactly the offending bit, but it looks like anything that touches the SP oject model causes the exception, including the RunWithElevatedPrivileges method.
update2: I still don't know the real reason this was failing, but it was happening when I was trying to add the web part. After setting breakpoints in the debugger, I realized that the constructor was being called twice; the first time, it all worked exactly as expected, but the second time was when the exception was being thrown. I still have no idea why. I found two ways around this: move the offending code out of the constructor into a later point in the lifecycle of the web part, or comment out the code to add the web part, then uncomment it and redeploy.
Apparently, the reason this "worked 3 days ago" was because I had added my web part to a page a long time ago, and then added the above code to the constructor. Since the web part was already added, I never saw any problems. Later, when I recently had to rebuild the site and add the web part to the page again, this problem manifested itself. So technically, it didn't "work" before, I just wasn't doing the thing that made it misbehave.
Anyway, like I said - I still don't know the true cause of the exception, so answers along those lines are still welcome.
The problem could occur if you try to work with SharePoint objects which were created outside of the RunWithElevatedPrivileges() method, and therefore still hold their old security context. In your case you use a SPUser object which was not created within the RunWithElevatedPrivileges() method.
To work around, you should create the object you want to work with within the delegate. Safe Ids or URLs outside of the delegate, to use them for recreating the objects. E.g.: safe the URL or ID of a SPSite object and use it to create it again within the delegate.
public void Demo()
{
string siteURL = SPContext.Current.Site.Url;
SPSecurity.RunWithElevatedPrivileges(delegate(){
using (SPSite safeSite = new SPSite(siteURL))
{
// place your code here ...
}
});
}
Perhaps you could post the stack trace so we can get some more information.

Resources