Sqlite atomic operations - c#

I run 5 applications which are using the same sqlite database (each application is different process). Unfortunately operations like GetEmptyPort have to be atomic to prevent returning same values. Right now I achieve that by using system Mutex, but I dont like this solution. Is there any built-in solution to do this in pure sqlite?
This is my code:
private static Mutex DB_MUTEX = new Mutex(false, "FOO_DB_MUTEX");
private T OnMutexWork<T>(Func<T> func)
{
try
{
DB_MUTEX.WaitOne();
return func.Invoke();
}
catch (Exception ex)
{
throw;
}
finally
{
DB_MUTEX.ReleaseMutex();
}
}
private SQLiteConnection GetConnection()
{
return new SQLiteConnection(databasePath);
}
private int GetEmptyPort(int min, int max)
{
return OnMutexWork<int>(() =>
{
using (var conn = GetConnection())
{
var allPorts = conn.Table<Port>()
.ToList();
for (int i = min; i <= max; i++)
{
if (!allPorts.Any(x => x.Value == i))
{
var item = new Port() { Value = i};
conn.Insert(item);
return i;
}
}
throw new Exception("Couldn't find empty port");
}
});
}
I tried what #Shawn Suggested:
private int GetEmptyPort(int min, int max)
{
using (var conn = GetConnection())
{
conn.RunInTransaction(() =>
{
var allPorts = conn.Table<Port>()
.ToList();
for (int i = min; i <= max; i++)
{
if (!allPorts.Any(x => x.Value == i))
{
var item = new Port() { Value = i};
conn.Insert(item);
return i;
}
}
});
throw new Exception("Couldn't find empty port");
}
}
But I am getting SQLite.SQLiteException: 'Busy' error when accessing database from different connections.

Related

C# intersect with lists

Working on a leetcode.com problem I tried the following approach with included the correct results with one duplicate. The code is supposed to find all possibilities of 3 numbers that equal zero without any duplicates.
I am looking for dupes in a list of lists using this if statement:
if(!returnList.Where(x=>x.Intersect(fullResult).Count()==3).Any())
This filters dupes in all but one case. Does anyone know why or perhaps a better way to eliminate dupes from a list of lists?
it will consistently not filter -1, -1, 2 which is a valid set but returned 2 times.
Paste into a console app to recreate.
class Program
{
static void Main(string[] args)
{
var output = ThreeSum(new int[] { -1, 0, 1, 2, -1, -4 });
foreach(var outie in output)
Console.WriteLine(String.Format("{0}, {1}, {2}", outie[0], outie[1], outie[2]));
Console.Read();
}
static public IList<IList<int>> ThreeSum(int[] nums)
{
List<int> lookup = new List<int>();
foreach (int i in nums)
{
lookup.Add(i);
}
IList<IList<int>> returnList = new List<IList<int>>();
for (var i = 0; i < nums.Count(); i++)
{
var result = TwoSum(i, lookup);
if (result != null)
{
var fullResult = new List<int>() { nums[i], nums[result[0]], nums[result[1]] };
if(!returnList.Where(x=>x.Intersect(fullResult).Count()==3).Any())
{
returnList.Add(fullResult);
}
}
}
return returnList;
}
static private int[] TwoSum(int thirdnumIndex, List<int> nums)
{
var target = nums[thirdnumIndex];
for (var i = 0; i < nums.Count(); i++)
{
var comp = (target + nums[i]) * -1;
if (nums.Contains(comp))
{
var indexOfComp = nums.IndexOf(comp);
if (indexOfComp == i || indexOfComp == thirdnumIndex)
{
return null;
}
return new int[] { i, indexOfComp };
}
}
return null;
}
}
Using Sort and SequenceEqual should work
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main(string[] args)
{
var output = ThreeSum(new int[] { -1, 0, 1, 2, -1, -4 });
foreach (var outie in output)
{
Console.WriteLine($"{outie[0]}, {outie[1]}, {outie[2]}");
}
Console.Read();
}
private static IList<IList<int>> ThreeSum(int[] nums)
{
var lookup = new List<int>(nums);
var returnList = new List<IList<int>>();
for (var i = 0; i < nums.Length; i++)
{
var result = TwoSum(i, lookup);
if (result != null)
{
var fullResult = new List<int> { nums[i], nums[result[0]], nums[result[1]] };
fullResult.Sort();
if (!returnList.Any(b => b.SequenceEqual(fullResult)))
{
returnList.Add(fullResult);
}
}
}
return returnList;
}
private static int[] TwoSum(int thirdnumIndex, List<int> nums)
{
var target = nums[thirdnumIndex];
for (var i = 0; i < nums.Count; i++)
{
var comp = (target + nums[i]) * -1;
if (nums.Contains(comp))
{
var indexOfComp = nums.IndexOf(comp);
if (indexOfComp == i || indexOfComp == thirdnumIndex)
{
return null;
}
return new[] { i, indexOfComp };
}
}
return null;
}
}

Cassandra CSharp driver batch statement failing

I am trying to use a batch statement instead of a single binded insert statement.
Even though this is a very small change this fails and I am not looking for a good way for the error handling and to find out which part is the issue. One issue is definetly that the Java API has a getStatements method which is missing in the C# driver.
The pseudo code looks like this:
private BatchStatement batchStatement = new BatchStatement();
private const int blockingFactor = 5;
private int i = 0;
private object locker = new object();
public CassandraBufferHandler()
{
Cluster = Cluster.Builder().AddContactPoints("localhost").Build();
Session = Cluster.Connect("my_keyspace");
InsertStatement = Session.Prepare("Insert into ticks (instrumentcode, timestamp, type, exchange, price, volume) values(?,?,?,?,?,?) if not exists;");
}
public void OnEvent(TickCassandra tickCassandra, long sequence, bool endOfBatch)
{
try
{
lock (locker)
batchStatement.Add(
InsertStatement.Bind(tickCassandra.Instrumentcode,
tickCassandra.Timestamp,
tickCassandra.Type,
tickCassandra.Exchange,
tickCassandra.Price,
tickCassandra.Volume));
if (i++ % blockingFactor == 0)
{
BatchStatement tmp;
lock (locker)
{
tmp = batchStatement;
tmp.EnableTracing();
batchStatement = new BatchStatement();
}
Session.ExecuteAsync(tmp).ContinueWith(t =>
{
if (t.Exception != null)
{
ErrorCount++;
Log.Error(t.Exception.Message + tmp.ToString());
}
else
InsertCount++;
});
}
}
catch (Exception ex)
{
Log.Error("Exception:" + ex);
Active = false;
}

How to use an object from try in catch - c#

I want to use an object in catch block, which get me an exception in try block. I'm parsing some strings to int and need to catch the exception when it's impossible and see, what object was mistaken and in what line. Is that possible or not?
Some code dor example. Thanks.
static void Main(string[] args)
{
var result = Parse(new List<string>() { "3;5;7", "qwe;3;70" });
}
public static List<int[]> Parse(List<string> list)
{
try
{
return list.Select(str => str.Split(';'))
.Select(str => Tuple.Create(int.Parse(str[0]), int.Parse(str[1]), int.Parse(str[2])))
/// something happening
.ToList();
}
catch
{
//here in braces I want to know, which element was wrong
//"qwe" and whole line "qwe;3;70"
throw new FormatException($"Wrong line [{}]");
}
}
Declare the line and value item counters outside the try/catch block and increase them in the LINQ expression body:
public static List<int[]> Parse(List<string> list)
{
int line = 0;
int item = 0;
try
{
return list
.Select(str => {
line++;
item = 0;
return str
.Split(';')
.Select(i => { item++; return int.Parse(i); })
.ToArray();
})
.ToList();
}
catch
{
throw new FormatException($"Wrong line [{line}]; item [{item}]");
}
}
Demo: https://dotnetfiddle.net/uGtw7A
You need a reference to the object causing the exception. However as the instance lives only in the scope of the try-block you can´t access it any more (try and catch don´t share the same scope and thus can´t access the same variables) unless you´d declare the reference to that instance outside the try-bloc
As already mentioned in the comments you should use a normal foreach-loop to have access to the current line:
public static List<int[]> Parse(List<string> list)
{
var result = new List<int[]>();
foreach(var str in list)
{
try
{
var values = str.Split(';');
result.Add(Tuple.Create(
int.Parse(values[0]),
int.Parse(values[1]),
int.Parse(values[2]))
);
}
catch
{
//here in braces I want to know, which element was wrong
throw new FormatException($"Wrong line " + str");
}
}
return result;
}
However you can simply avoid all those exceptions by useing TryParse instead which returns false if parsing failed. So this boils down to something like this:
var values = str.Split(';');
int v0, v1, v2;
if(int.TryParse(values[0], out v0 &&
int.TryParse(values[1], out v1 &&
int.TryParse(values[2], out v2 &&))
result.Add(Tuple.Create(v0, v1, v2));
else
throw new FormatException($"Wrong line " + str");
I recommend manually looping through, splitting the data, checking you have enough elements, and then using TryParse on the numbers. I know this is a departure from using Linq, but it's the better way to do this with error checking:
public static List<int[]> Parse(List<string> list)
{
if (list == null)
{
throw new ArgumentNullException("list");
// you can use nameof(list) instead of "list" in newer versions of C#
}
List<int[]> result = new List<int[]>();
// Loop through the entries
for (int i = 0; i < list.Count; ++i)
{
// Be safe and check we don't have a null value
// I'm just skipping the 'bad' entries for now but
// you can throw an error, etc.
if (list[i] == null)
{
// do something about this? (an exception of your choosing, etc.)
continue;
}
// split the entry
string[] entryData = list[i].Split(';');
// check we have 3 items
if (entryData.Length != 3)
{
// do something about this?
continue;
}
// try to parse each item in turn
int a;
int b;
int c;
if (!int.TryParse(entryData[0], out a))
{
// do something about this?
continue;
}
if (!int.TryParse(entryData[1], out b))
{
// do something about this?
continue;
}
if (!int.TryParse(entryData[2], out c))
{
// do something about this?
continue;
}
// add to the results list
result.Add(new int[] { a, b, c });
}
// return the result
return result;
}
Scope is scope. Anything you define inside your try block and don't explicitly pass on is not going to be available in your catch block.
If you need this information you have to iterate manually over the list and try catch each attempt individually...
There are too many problems with your code, you're assuming that parameter list is not null and contains items that can be splitted in 3 strings, and that every string can be safely parsed to int.
If you not have all the above guaranties just check everything:
public static List<int[]> Parse(List<string> list)
{
if (list == null)
{
throw new ArgumentNullException(nameof(list));
}
var arrayOfStringArray = list
.Select(x => x.Split(';'))
.ToArray();
var resultList = new List<int[]>();
for (var i = 0; i < arrayOfStringArray.Length; i++)
{
var arrayOfString = arrayOfStringArray[i];
if (arrayOfString.Length != 3)
{
throw new InvalidOperationException("meaningfull message there!");
}
var arrayOfInt = new int[3];
for (var j = 0; j < arrayOfInt.Length; j++)
{
arrayOfInt[j] = TryParse(arrayOfString[j], i, j);
}
resultList.Add(arrayOfInt);
}
return resultList;
}
static int TryParse(string value, int line, int position)
{
int result;
if (!int.TryParse(value, out result))
{
throw new FormatException($"Item at position {line},{position} is invalid.");
}
return result;
}
I think that you just got a wrong approach here. Yes, using Tuple + Linq would be the laziest way to get your result but you can't generate custom errors as so.
Here is an example of how you can achieve something alike:
static void Main(string[] args)
{
var result = Parse(new List<string>() { "3;5;7", "qwe;3;70" });
}
public static List<Tuple<int, int, int>> Parse(List<string> list)
{
List<Tuple<int, int, int>> result = new List<Tuple<int, int, int>>();
int line = 0;
int errorCol = 0;
try
{
for (line = 0; line < list.Count; line++)
{
string[] curentLine = list[line].Split(';');
int result0, result1, result2;
errorCol = 1;
if (curentLine.Length > 0 && int.TryParse(curentLine[0], out result0))
errorCol = 2;
else
throw new Exception();
if (curentLine.Length > 1 && int.TryParse(curentLine[1], out result1))
errorCol = 3;
else
throw new Exception();
if (curentLine.Length > 2 && int.TryParse(curentLine[2], out result2))
result.Add(new Tuple<int, int, int>(result0, result1, result2));
else
throw new Exception();
}
return result;
}
catch
{
//here in braces I want to know, which element was wrong
throw new FormatException("Wrong line " + line + " col" + errorCol);
}
}
PS: Line and column start at 0 here.

Is that logic to reset the Lists and call Init() over again if there was an exception with the download/s?

And how can i report to the user that there was a problem and that it's trying over again ? And should i just do it like i'm doing it now reseting everything and calling Init() again or should i use some timer and wait some seconds before trying again ?
In the class i did:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Xml;
using HtmlAgilityPack;
using System.ComponentModel;
namespace TestingDownloads
{
class ExtractImages
{
static WebClient client;
static string htmltoextract;
public static List<string> countriescodes = new List<string>();
public static List<string> countriesnames = new List<string>();
public static List<string> DatesAndTimes = new List<string>();
public static List<string> imagesUrls = new List<string>();
static string firstUrlPart = "http://www.sat24.com/image2.ashx?region=";
static string secondUrlPart = "&time=";
static string thirdUrlPart = "&ir=";
public class ProgressEventArgs : EventArgs
{
public int Percentage { get; set; }
public string StateText { get; set; }
}
public event EventHandler<ProgressEventArgs> ProgressChanged;
public void Init()
{
object obj = null;
int index = 0;
ExtractCountires();
foreach (string cc in countriescodes)
{
// raise event here
ProgressChanged?.Invoke(obj,new ProgressEventArgs{ Percentage = 100 * index / countriescodes.Count, StateText = cc });
ExtractDateAndTime("http://www.sat24.com/image2.ashx?region=" + cc);
index +=1;
}
ImagesLinks();
}
public void ExtractCountires()
{
try
{
htmltoextract = "http://sat24.com/en/?ir=true";//"http://sat24.com/en/";// + regions;
client = new WebClient();
client.DownloadFile(htmltoextract, #"c:\temp\sat24.html");
client.Dispose();
string tag1 = "<li><a href=\"/en/";
string tag2 = "</a></li>";
string s = System.IO.File.ReadAllText(#"c:\temp\sat24.html");
s = s.Substring(s.IndexOf(tag1));
s = s.Substring(0, s.LastIndexOf(tag2) + tag2.ToCharArray().Length);
s = s.Replace("\r", "").Replace("\n", "").Replace(" ", "");
string[] parts = s.Split(new string[] { tag1, tag2 }, StringSplitOptions.RemoveEmptyEntries);
string tag3 = "<li><ahref=\"/en/";
for (int i = 0; i < parts.Length; i++)
{
if (i == 17)
{
//break;
}
string l = "";
if (parts[i].Contains(tag3))
l = parts[i].Replace(tag3, "");
string z1 = l.Substring(0, l.IndexOf('"'));
if (z1.Contains("</ul></li><liclass="))
{
z1 = z1.Replace("</ul></li><liclass=", "af");
}
countriescodes.Add(z1);
countriescodes.GroupBy(n => n).Any(c => c.Count() > 1);
string z2 = parts[i].Substring(parts[i].LastIndexOf('>') + 1);
if (z2.Contains("&"))
{
z2 = z2.Replace("&", " & ");
}
countriesnames.Add(z2);
countriesnames.GroupBy(n => n).Any(c => c.Count() > 1);
}
}
catch (Exception e)
{
if (countriescodes.Count == 0)
{
countriescodes = new List<string>();
countriesnames = new List<string>();
DatesAndTimes = new List<string>();
imagesUrls = new List<string>();
Init();
}
}
}
public void ExtractDateAndTime(string baseAddress)
{
try
{
var wc = new WebClient();
wc.BaseAddress = baseAddress;
HtmlDocument doc = new HtmlDocument();
var temp = wc.DownloadData("/en");
doc.Load(new MemoryStream(temp));
var secTokenScript = doc.DocumentNode.Descendants()
.Where(e =>
String.Compare(e.Name, "script", true) == 0 &&
String.Compare(e.ParentNode.Name, "div", true) == 0 &&
e.InnerText.Length > 0 &&
e.InnerText.Trim().StartsWith("var region")
).FirstOrDefault().InnerText;
var securityToken = secTokenScript;
securityToken = securityToken.Substring(0, securityToken.IndexOf("arrayImageTimes.push"));
securityToken = secTokenScript.Substring(securityToken.Length).Replace("arrayImageTimes.push('", "").Replace("')", "");
var dates = securityToken.Trim().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
var scriptDates = dates.Select(x => new ScriptDate { DateString = x });
foreach (var date in scriptDates)
{
DatesAndTimes.Add(date.DateString);
}
}
catch
{
countriescodes = new List<string>();
countriesnames = new List<string>();
DatesAndTimes = new List<string>();
imagesUrls = new List<string>();
this.Init();
}
}
public class ScriptDate
{
public string DateString { get; set; }
public int Year
{
get
{
return Convert.ToInt32(this.DateString.Substring(0, 4));
}
}
public int Month
{
get
{
return Convert.ToInt32(this.DateString.Substring(4, 2));
}
}
public int Day
{
get
{
return Convert.ToInt32(this.DateString.Substring(6, 2));
}
}
public int Hours
{
get
{
return Convert.ToInt32(this.DateString.Substring(8, 2));
}
}
public int Minutes
{
get
{
return Convert.ToInt32(this.DateString.Substring(10, 2));
}
}
}
public void ImagesLinks()
{
int cnt = 0;
foreach (string countryCode in countriescodes)
{
cnt++;
for (; cnt < DatesAndTimes.Count(); cnt++)
{
string imageUrl = firstUrlPart + countryCode + secondUrlPart + DatesAndTimes[cnt] + thirdUrlPart + "true";
imagesUrls.Add(imageUrl);
if (cnt % 10 == 0) break;
}
}
}
}
}
In both cases where i'm using try and catch if it's getting to the catch i'm trying over again the whole operation by reseting the Lists and calling Init() again.
Then in form1
ExtractImages ei = new ExtractImages();
public Form1()
{
InitializeComponent();
ProgressBar1.Minimum = 0;
ProgressBar1.Maximum = 100;
backgroundWorker1.RunWorkerAsync();
}
events of backgroundworker
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (backgroundWorker1.CancellationPending == true)
{
e.Cancel = true;
return; // this will fall to the finally and close everything
}
else
{
ei.ProgressChanged += (senders, eee) => backgroundWorker1.ReportProgress(eee.Percentage, eee.StateText);
ei.Init();
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressBar1.Value = e.ProgressPercentage;
label7.Text = e.UserState.ToString();
label8.Text = e.ProgressPercentage + "%";
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
ProgressBar1.Value = 100;
}
else
{
}
}
Another thing not sure if it's a problem. When there is no a problem with the class i see in form1 in label7 all the codes running from the first to the last.
But the progressBar1.Value and label8 both are getting only to 97% so i need in the completed event to add the progressBar1.Value = 100; is that fine or there is a problem with the reporting calculation in the class ?
For the 1st question:
Better catch the exception at client side and display the error msg, 'cause you probably need to control your program behavior accrodingly when sth went wrong.
Consider this: if the DOM struct of the page changed, according to you code, your program probably throw expections, with each exception catching, client.DownloadFile is excuted for one time, if this happens, u will need to know what go wrong, and if u donot change ur code behavior, such hi-freq client.DownloadFile excution will cause the firewall of the website block ur ip for a while.
Add a timer at client side is a good idea i think.
For the 2nd one:
did u define how to handle RunWorkerCompleted event?

My Recursive method has a stackoverflow when used with a particular dataset

I am trying to search a List for combinations that add up to a particular value (I've tried using Knapsack but it was checking too much for my particular scenario and taking too long). The code works and finds matches for most of the datasets I throw at it but fails for some others.
All of my List s don't have more that 100 entries.
I had assumed that because my recursive method is wrapped in a sensible if statement that a stack overflow would not occur but it blows up on this line: if(x.Sum(y => y.Amount) == limit)
Here is my code:
private static void Check(List<double> trackedListToCopy, double limit)
{
List<CheckerObject> trackedList = new List<CheckerObject>();
int idCount = 1;
trackedListToCopy.ForEach(x => {
trackedList.Add(new CheckerObject() { Amount = x, Id = idCount});
idCount++;
});
List<List<CheckerObject>> possiblitiesToCheck = new List<List<CheckerObject>>();
if (trackedList.FirstOrDefault(x=>x.Amount == limit) != null)
{
Console.WriteLine("Exact match found");
return;
}
trackedList.ForEach(item =>
{
var listToCheck = new List<CheckerObject>();
if (trackedList.First().Id == item.Id)
return;
listToCheck.Add(trackedList.First());
listToCheck.Add(item);
possiblitiesToCheck.Add(listToCheck);
if (possiblitiesToCheck.Any(x => x.Sum(y => y.Amount) == limit))
{
List<CheckerObject> match = possiblitiesToCheck.First(x => x.Sum(y => y.Amount) == limit);
Console.WriteLine("Match found with 2 entries" + match);
return;
}
});
var baseList = new List<List<CheckerObject>>(possiblitiesToCheck);
SubsequentCheck(baseList, trackedList, limit);
}
private static void SubsequentCheck(List<List<CheckerObject>> baseList, List<CheckerObject> trackedList, double limit)
{
//List<List<CheckerObject>> copy = new List<List<CheckerObject>>(baseList);
trackedList.ForEach(item => {
baseList.ForEach(x =>{
if (!x.Contains(item))
{
x.Add(item);
if(x.Sum(y => y.Amount) == limit)
{
string show = "";
x.ForEach(n => { show += n.Amount + ","; });
Console.WriteLine(String.Format("Match Found from {0}", show));
}
if (x.Sum(y => y.Amount) < limit)
{
SubsequentCheck(new List<List<CheckerObject>>(baseList), trackedList, limit);
}
}
});
});
}
public class CheckerObject
{
public int Id { get; set; }
public double Amount { get; set; }
}
Any and all help is as always greatly appreciated.
Change
private static void SubsequentCheck(List<List<CheckerObject>> baseList, List<CheckerObject> trackedList, double limit)
to
private static void SubsequentCheck(List<List<CheckerObject>> baseList, List<CheckerObject> trackedList, double limit, int recursiveDepth = 0)
and
if (x.Sum(y => y.Amount) < limit)
{
SubsequentCheck(new List<List<CheckerObject>>(baseList), trackedList, limit);
}
to
if (x.Sum(y => y.Amount) < limit)
{
SubsequentCheck(new List<List<CheckerObject>>(baseList), trackedList, limit, recursiveDepth + 1);
}
Then log everything or put a conditional breakpoint on recursive depth greater than some sensible limit.
Also change the .ForEach calls to foreach loops so that the loop can be stopped properly for efficiency (the return statement does not end the loop in this case)
Also change the Lists for Hashsets when calling .Contains so frequently if performance is an issue

Categories