Lucene.net - singleton + queue = write.lock issue - c#

I have a strange problem. Here's the scenario:
I use Lucene.net, and I have the IndexWriter object as a singleton, because of the write.lock file. Also, only one thread is accessing to that object thanks to the RabbitMQ.
But I still get the error System.IO.IOException: The process can not access the file "e:\MyIndex\write.lock" because it is being used by another process.
I thought it can be caused by IIS pool recycle, as mentioned here https://medium.com/#ShamreshKhan/turning-off-iis-app-pool-overlap-recycle-6d2591faa312#.qnflhui4z but it didn't fix the problem. What else do I have to check what can cause the problem ?
My IndexWirter singleton:
public class Singletons
{
private Singletons()
{
if (directoryMyTemp == null)
directoryMyTemp = FSDirectory.Open(new DirectoryInfo(luceneMyDir));
if (IndexWriter.IsLocked(directoryMyTemp))
IndexWriter.Unlock(directoryMyTemp);
//just to be sure
lockFilePath = Path.Combine(luceneMyDir, IndexWriter.WRITE_LOCK_NAME);
if (File.Exists(lockFilePath))
File.Delete(lockFilePath);
}
private static readonly object singLock = new object();
private static readonly Lazy<Singletons> lazy = new Lazy<Singletons>(() => new Singletons());
private static readonly Lazy<IndexWriter> MyWriterLazy = new Lazy<IndexWriter>(() => new IndexWriter(MainInstance.MyDirectory, Workers.GetAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED));
public static IndexWriter MyInstance
{
get
{
return MyWriterLazy.Value;
}
}
public static Singletons MainInstance
{
get
{
return lazy.Value;
}
}
private static FSDirectory directoryMyTemp;
public FSDirectory MyDirectory
{
get
{
return directoryMyTemp;
}
}
}
index rebuild:
Singletons.MyInstance.DeleteAll();
for (int i = 0; i < count; i++)
{
try
{
//document update
}
catch (Exception)
{
Singletons.MyInstance.Rollback();
throw;
}
}
Singletons.MyInstance.Commit();

Related

Is it possible to have a singleton exist accross different projects within a solution?

I am attempting to communicate information between two different projects. One is a remoting server and the other a WPF application. I have created a singleton class but have noticed that each time one project calls the GetInstance method it creates a new instance of the singleton. Is it possible to have a singleton accross projects as it doesn't seem it is and if that is the case, why is that?
Below is my code for the singleton
public class CommunicationSingleton
{
private int jobCount = 0;
private Job jobInProgress;
private List<Job> jobs = new List<Job>();
private static CommunicationSingleton instance = new CommunicationSingleton();
static readonly object obj = new object();
private CommunicationSingleton() { }
public static CommunicationSingleton GetInstance()
{
lock (obj)
{
if (instance == null)
{
return instance = new CommunicationSingleton();
}
else
{
return instance;
}
}
}
public void AddJob(Job job)
{
jobs.Add(job);
}
public List<Job> GetJobs()
{
return jobs;
}
public void IncreaseJobCount(int jobCount)
{
this.jobCount += jobCount;
}
public int GetJobCount()
{
return jobCount;
}
public void JobInProgress(Job jobInProgress)
{
this.jobInProgress = jobInProgress;
}
public Job GetJobInProgress()
{
return jobInProgress;
}
}

C# Singleton with a Disposable object

Suppose I have a Singleton that loads resources into memory when created, and performs operation on the data when callings its methods.
Now suppose, that I want to have the ability to tell the Singleton to release those resources, as I don't expect to be using them in the near future, but also be able to load those resources back in, when the time comes. And I want it all to be thread safe.
What would be the best way to aproach this problem?
Would this example work?:
// Singleton implementation
...
private IDisposable resource;
private bool loadingResources;
private IDisposable Resource {
get => resource ?? throw new CustomException();
}
// Method A
public void A() {
var resource = Resource; // Throws CustomException if resource is null
// Do stuff
}
// Method B
public void B() {
var resource = Resource;
// Do stuff
}
public void ReleaseResources() {
if (resource != null)
lock (thislock) {
//resource.Dispose();
resource = null;
}
}
public void LoadResources() {
if (!loadingResources && resource == null)
lock (thislock)
if (!loadingResources && resource == null)
{
loadingResources = true;
// Load resources
resource = CreateResource();
loadingResources = false;
}
}
I would suggest separating the resource handling from the actual usage. Assuming the resource requires disposal this could look something like:
public class DisposableWrapper<T> where T : IDisposable
{
private readonly Func<T> resourceFactory;
private T resource;
private bool constructed;
private object lockObj = new object();
private int currentUsers = 0;
public DisposableWrapper(Func<T> resourceFactory)
{
this.resourceFactory = resourceFactory;
}
public O Run<O>(Func<T, O> func)
{
lock (lockObj)
{
if (!constructed)
{
resource = resourceFactory();
constructed = true;
}
currentUsers++;
}
try
{
return func(resource);
}
catch
{
return default;
}
finally
{
Interlocked.Decrement(ref currentUsers);
}
}
public void Run(Action<T> action)
{
lock (lockObj)
{
if (!constructed)
{
resource = resourceFactory();
constructed = true;
}
currentUsers++;
}
try
{
action(resource);
}
finally
{
Interlocked.Decrement(ref currentUsers);
}
}
public bool TryRelease()
{
lock (lockObj)
{
if (currentUsers == 0 && constructed)
{
constructed = false;
resource.Dispose();
resource = default;
return true;
}
return false;
}
}
}
If the resource does not require disposal I would suggest to instead use lazy<T>. Releasing resources would simply mean replacing the existing lazy object with a new one. Letting the old object be cleaned up by the garbage collector.

Issue in C# singleton with multi threading: a variable not intialized

This is a simplified version of production code and running in multi thread with singleton. Compared to traditional singleton the additional thing is that I initialized client in the lock section.
When I trying to get the client by: Client client = Singleton.Instance.GetClient();, there is chance that client can be null (but the chance is very small).
public class Client
{
public int Value { get; set; } = 10;
}
public class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
private Client client = null;
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
// Here is the interesting part!
instance.InitClient();
}
}
}
return instance;
}
}
private void InitClient()
{
this.client = new Client();
}
public Client GetClient()
{
return this.client;
}
}
This is how I testing it:
static void Main(string[] args)
{
Console.WriteLine("Input thread count: ");
int threadCount = Int32.Parse(Console.ReadLine().Trim());
List<Task> tasks = new List<Task>(threadCount);
for (int i = 0; i < threadCount; ++i)
{
tasks.Add(Task.Factory.StartNew(() => DoStuff()));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("All threads complete");
}
private static void DoStuff()
{
Client client = Singleton.Instance.GetClient();
if (client.Value != 10)
{
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}.");
}
}
And client can be null in occasionlly:
But when I moved the InitClient() into the private constructor of Singleton, I never meet the situation that client is null:
private Singleton()
{
this.InitClient();
}
I don't have any clue what is difference and what is wrong, thanks for the helping!
As soon as you call instance = new Singleton() inside the lock, "instance" is no longer null, meaning separate (threaded) calls to Singleton.Instance returns immediately, and a call to GetClient on that instance would be a race condition with the InitClient from the first call.
Initializing inside the constructor ensures "Instance" itself is initialized as soon as it's created. So subsequent calls from separate threads wouldn't race against anything.

DI container giving new instance every time?

It seems my DI container makes a new instance for ChromeDriver (IWebDriver) each time I try and get it from the container? All of this happened after refactoring my code. I suddenly needed Selenium by reference for the methods below, otherwise, it wouldn't update the DOM throughout new page loads as I was passing it by value.
Here are the original methods before refactoring,
public static bool ElementExists(IWebDriver selenium, By selector)
{
try
{
selenium.FindElement(selector);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
public static void WaitForElements(IWebDriver selenium, List<By> selectors, string name = "")
{
new ConsoleLogger().Trace("Waiting for " + (string.IsNullOrEmpty(name) ? selectors.Count + " items" : name) + ", give us a second.");
while (selectors.Where(x => ElementExists(selenium, x)).Count() < selectors.Count)
{
Thread.Sleep(100);
}
}
I thought hmm, this is going to be a tricky one. I needed some sort of static instance that I could always pass by reference, I refactored it to this.
public static bool ElementExists(By selector)
{
var selenium = Reusables.GetServiceProvider().GetService<IWebDriver>();
try
{
selenium.FindElement(selector);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
Reusables class:
public static class Reusables
{
public static IDependencyProvider DependencyProvider;
public static IServiceProvider GetServiceProvider()
{
return DependencyProvider.BuildServiceProvider();
}
}
Program:
private static void Main(string[] args)
{
var diProvider = new DependencyProvider();
Reusables.DependencyProvider = diProvider;
Console.ForegroundColor = ConsoleColor.White;
Console.CancelKeyPress += (sender, eArgs) => {
QuitEvent.Set();
eArgs.Cancel = true;
};
Console.WriteLine();
Console.CursorVisible = false;
/*var config = serviceProvider.GetService<IConfigProvider>();
config.Load("https://kskdkskd.kdskdkk", new WebClient());*/
var scraper = Reusables.GetServiceProvider().GetService<IScraperHandler>();
scraper.Start();
QuitEvent.WaitOne();
}
Not sure if its needed, but here's how I register my dependencies:
public class DependencyProvider : ServiceCollection, IDependencyProvider
{
public DependencyProvider()
{
Register();
}
public void Register()
{
this.AddSingleton<IAuthProvider, AuthProvider>();
var options = new ChromeOptions();
options.AddArguments("--disable-notifications");
options.SetLoggingPreference(LogType.Browser, LogLevel.Off);
this.AddSingleton<IWebDriver>(provider =>
new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), options)
);
var links = File.ReadAllLines("***");
this.AddSingleton<IHttpHandler, HttpHandler>();
this.AddSingleton<IEnumerable>(stack => new Stack<string>(links.ToList()));
this.AddSingleton<IScraperHandler, ScraperHandler>();
this.AddSingleton<IConfigProvider, JsonConfigProvider>();
}
}
You are building a new service provider every time Reusables.GetServiceProvider is invoked. Which will result in a new provider each time, resulting in a new instance every time the new service provider gets a service.
If the goal is to have a single provider then a singleton is required.
public static class Reusables {
public static IDependencyProvider DependencyProvider;
private static Lazy<IServiceProvider> serviceProvider =
new Lazy<IServiceProvider>(() => DependencyProvider.BuildServiceProvider());
public static IServiceProvider GetServiceProvider() {
return serviceProvider.Value;
}
}
Not a big fan of the above design but it should work.

Mutex release issues in ASP.NET C# code

I'm not exactly sure how to address this issue. I have a mutex that is declared as such:
public class MyNamedLock
{
private Mutex mtx;
private string _strLkName;
public MyNamedLock(string strLockName)
{
_strLkName = strLockName;
//...
mtx = new Mutex(false, _strLkName, out bCreatedNew, mSec);
}
public bool enterLockWithTimeout(int nmsWait = 30 * 1000)
{
_nmsWaitLock = nmsWait;
//Wait
return mtx.WaitOne(nmsWait);
}
public void leaveLock()
{
_nmsWaitLock = 0;
//Release it
mtx.ReleaseMutex();
}
}
Then it is used in an ASP.NET page as such:
public class MyClass
{
private MyNamedLock gl;
public MyClass()
{
gl = new MyNamedLock("lock name");
}
public void funct()
{
try
{
//Enter lock
if (gl.enterLockWithTimeout())
{
//Do work
}
else
throw new Exception("Failed to enter lock");
}
finally
{
//Leave lock
gl.leaveLock();
}
}
}
This code doesn't give me any trouble in my dev environment but in the production it sometimes throws this exception:
Object synchronization method was called from an unsynchronized block
of code.
The description is kinda vague, but just doing the trace I found out that the exception is raised at the mtx.ReleaseMutex(); part. What does it mean and how to fix it?
You have some issues on your class, and on the way you use it.
You must release the mutex only if you have previous locked (and this is your error)
You need to Close and Dispose your opened mutex
Also is better to create it just before you going to use it and not when you create you class MyClass.
So I suggest at first look to change your class as:
public class MyNamedLock
{
private Mutex mtx = null;
private string _strLkName;
// to know if finally we get lock
bool cNeedToBeRelease = false;
public MyNamedLock(string strLockName)
{
_strLkName = strLockName;
//...
mtx = new Mutex(false, _strLkName, out bCreatedNew, mSec);
}
public bool enterLockWithTimeout(int nmsWait = 30 * 1000)
{
_nmsWaitLock = nmsWait;
bool cLock = false;
try
{
cLock = mtx.WaitOne(nmsWait, false);
cNeedToBeRelease = cLock;
}
catch (AbandonedMutexException)
{
// http://stackoverflow.com/questions/654166/wanted-cross-process-synch-that-doesnt-suffer-from-abandonedmutexexception
// http://msdn.microsoft.com/en-us/library/system.threading.abandonedmutexexception.aspx
cNeedToBeRelease = true;
}
catch (Exception x)
{
// log the error
Debug.Fail("Check the reason of fail:" + x.ToString());
}
return cLock;
}
public void leaveLock()
{
_nmsWaitLock = 0;
if (mtx != null)
{
if (cNeedToBeRelease)
{
try
{
mtx.ReleaseMutex();
cNeedToBeRelease = false;
}
catch (Exception x)
{
Debug.Fail("Check the reason of fail:" + x.ToString());
}
}
mtx.Close();
mtx.Dispose();
mtx = null;
}
}
}
This the way you must call that class:
public class MyClass
{
public MyClass()
{
}
public void funct()
{
var gl = new MyNamedLock("lock name");
try
{
//Enter lock
if (gl.enterLockWithTimeout())
{
//Do work
}
else
throw new Exception("Failed to enter lock");
}
finally
{
//Leave lock
gl.leaveLock();
}
}
}
In your finally block you're releasing the mutex regardless of whether you actually acquired it in your try block.
In
try
{
//Enter lock
if (gl.enterLockWithTimeout())
{
//Do work
}
else throw new Exception("Failed to enter lock");
}
finally
{
//Leave lock
gl.leaveLock();
}
if gl.enterLockWithTimeout returns false, you will throw an exception but then try to release the lock in the finally block.

Categories