DBUP - Running Script in Order - c#

I am trying out DBUP and can't seem to get it working. I have split my scripts into different directory and prefixed them with the number order they are suppose to be run. As far I know DBUP is suppose to run the script based on the Directory lexicographically, then process the files within. That is not happening it seems to be treating the files as if they are all in one big directory and running them in lexicographical order regardless of the the scripts directory. So I have data script trying to insert data into tables that have not been created yet.
var upgrader = DeployChanges.To.SqlDatabase(connectionString)
.WithScriptsFromFileSystem(Path.Combine(dbScripts, "00-PreDeployment"))
.WithScriptsFromFileSystem(Path.Combine(dbScripts, "01-Tables"))
.WithScriptsFromFileSystem(Path.Combine(dbScripts, "02-Views"))
.WithScriptsFromFileSystem(Path.Combine(dbScripts, "03-Functions"))
.WithScriptsFromFileSystem(Path.Combine(dbScripts, "04-StoredProcedures"))
.WithScriptsFromFileSystem(Path.Combine(dbScripts, "05-Data"))
.JournalToSqlTable("dbo", "SchemaVersion")
.LogToConsole()
.Build();
Am I missing something? Is the solution just to prefix all my script with the directory order?
EXAMPLE:
I have script name called Statuses.sql in the folder 01-Tables that create the Status table, and a script named Add_Status.sql in the 05-Data that populates the status table. What I expected to happen was the Status.sql get executed first then Add_Status.sql because of the directory "versioning" 01 comes before 05. But what was happening was Add_Status.sql was being excuted before the status table is created becuase it was treating every file as if they are in the same directory, 'A' comes before 'S'

Related

How not to allow running some parts of a script by different users at the exact moment of time?

everyone!
I do a small project for my company and I use C#. I have a script for my project. But before this day, my colleagues and I had an idea that the script would be used by users one by one. For example, if there are a user A and user B, there can be the order where the user B runs the script and only then the user A can run the script.
Today the decision was made to give the users the possibility to run the script freely without the predetermined order. And now I have some thoughts. Here the part of the script:
if (Directory.Exists(#"H:\" + doc_number + #"\detached") == false)
{
Directory.CreateDirectory(#"H:\" + doc_number + #"\detached");
File.WriteAllBytes(#"H:\" + doc_number + #"\detached\1.cms", signature_bytes);
}
else
{
string[] files = Directory.GetFiles(#"H:\" + doc_number + #"\detached"); int files_number = files.Length;
File.WriteAllBytes(#"H:\" + doc_number + #"\detached\" + Convert.ToString(files_number + 1) + ".cms", signature_bytes);
}
Firstly, there is a check of the existence of a directory. If it doesn't exist, the directory will be created and the first file will be added there. Otherwise, we just count the number of files in the directory and then create a new file with a name which is the number of the files in the folder plus one.
However, I'm thinking about the situation when the user A and the user B were at the beginning of this part of the script at the same time and the condition for both would be positive so it wouldn't be executed correctly. Or if one of them started running this part earlier but his or her PC was less powerful so while creating the directory another user would go through the condition, counting files and start creating a file before the first user which would be also incorrect.
I don't know how likely one of these situations are. if so, how can I solve it?
Indeed, you can run into concurrency issues. And you are correct that you can't rely on the existence of a directory to decide what branch to take in your if statement because you might have operations execute in this order:
User A: Checks for directory. Does not exist.
User B: Checks for directory. Does not exist.
User A: Creates directory, enters if branch.
User B: Creates directory, enters if branch.
If the code was running in one process on one machine but in multiple threads, you could use a lock statement.
If the code was running on different processes on the same machine, you could use a cross-process coordination method such as a Mutex.
The question implies that the code runs on different computers but accesses the same file system. In this case, a lock file is a common mechanism to coordinate access to a shared resource. In this approach, you would attempt to create a file and lock it. If that file already exists and is locked by another process, you know someone else got there first. Depending on your needs, a common scenario is to wait for the lock on the file to go away then acquire the lock yourself and continue.
This strategy also works for the other 2 cases above, though is less efficient.
For information about how to create a file with a lock, see
How to lock a file with C#?
There are some issues with your code. For example, what would happen if a file is deleted? The number of files in the directory would be different than the number of the last file, and you can end up trying to write a file that already exists. Also, please use Path.Combine to create paths, it is safer. You also don't need to check if the directory exists, since Directory.Create will do nothing if it already exists.
Common for all solutions bellow:
string baseDir = Path.Combine("H:",doc_number, "detached");
Directory.Create(baseDir);
If you just want any number of users to create files in the same directory, some solutions that are more safe:
Use a GUID:
var guid = Guid.NewGuid();
var file = Path.Combine(baseDir, $"{guid}.cms");
File.WriteAllBytes(file, signature_bytes);
Iterate, trying to create a new file:
bool created = false;
int index = 1;
while(!created)
{
//Check first if the file exists, and gets the next available index
var file = Path.Combine(baseDir, $"{index}.cms");
while(File.Exists(file))
{
file = Path.Combine(baseDir, $"{++index}.cms");
}
//Handle race conditions, if the file was created after we checked
try
{
//Try create the file, not allowing others to acess it while open
using var stream = File.Open(file,FileMode.CreateNew,FileAccess.Write,FileShare.None);
stream.Write(signature_bytes);
created = true;
}
catch (IOException) //If the file already exists, try the next index
{
++index;
}
}

pyinstaller .exe works locally but fails when called by C#?

I have created a script using Python2.7 and compiled it using pyinstaller into an exe of the same name, in this case "GeneralStats.py" turns into "GeneralStats.exe" using --onefile and -w arguments.
When called with C# I use:
var pythonDirectory = (Directory.GetCurrentDirectory());
var filePathExe1 = Path.Combine(pythonDirectory + "\\Python\\GeneralStats.exe");
Process.Start(filePathExe1);
When called outside of C#, so in my local files I can run the .exe and the result is a text file with lots of values in (Running correctly).
However, when ran with C# in this format, I get an error that "GeneralStats returned -1!"
Which I have had issues with before, but it was a simple python error that when I returned to my code and ran it, I would receive an error that I overlooked.
This time my python code returns no errors and works outside of C#.
Any ideas of why this could be? I can provide any code or file directories necessary, please just ask if you feel it would help with debugging.
EDIT:
Solved by removing:
var filePathExe1 = Path.Combine(pythonDirectory + "\\Python\\GeneralStats.exe");
Process.Start(filePathExe1);
And replacing with:
ProcessStartInfo _processStartInfo = new ProcessStartInfo();
_processStartInfo.WorkingDirectory = Path.Combine(pythonDirectory + "\\Python");
_processStartInfo.FileName = #"GeneralStats.exe";
_processStartInfo.CreateNoWindow = true;
Process myProcess = Process.Start(_processStartInfo);
You need to set the working directory for the Process - it is probably trying to load files from its working directory but isn't finding them.
See, e.g. this:
Use the ProcessStartInfo.WorkingDirectory property to set it prior to starting the process. If the property is not set, the default working directory is %SYSTEMROOT%\system32.
Set it to the path where GeneralStats.exe is.

Stand alone ".exe" matlab file not saving images

I'm trying to create an ".exe" file that will read some sort of data(for a known path), and will plot it one time as "bplot" and the other time as "histogram".
The code works fine as I run it from the editor, and even after I've made an ".exe" file. The problem begins when I try to run it from a "C#" code with the command "Process.Start(#"my_path.exe")". It seems like it runs the code and I can see the figures that are made, but it doesn't save the pictures.
My matlab code is:
clear
clc
P = csvread('my_path\test_csv.csv');
SP = bplot(P);
pause (3);
saveas(figure(1),[pwd '\picture1.jpeg']);
pause (3)
B = csvread('my_path\test2_csv.csv');
histogram(B);
pause (3)
saveas(figure(1),[pwd '\picture2.jpeg']);
pause (3)
close
clear
clc
The "bplot" is an external function that I downloaded.
Any ideas how to save it in other way so the stand alone application will save the images when I call it from C# code?
Try using the syntax with ProcessStartInfo parameter (see here), rather than syntax with the path the file directly.
Indeed if not setting ProcessStartInfo.WorkingDirectory, it will be considered to be %SYSTEMROOT%\System32 (for which you don't have write access as normal user)
var startInfo = new ProcessStartInfo(#"my_path.exe");
startInfo.WorkingDirectory= .... you exe dir or something else....;
Process.Start(startInfo);

Passing file name with spaces to SPOOL command using SQL Plus gives SP2-0768 Illegral SPOOL command error

My sql file contains
`SPOOL &1;
//sql code to execute
SPOOL OFF;`
The sql file is executed using SQL Plus and SQL Plus is being called from C# code using Process.Start... Code snipped
`var m_StartInfo = new ProcessStartInfo();
m_StartInfo.FileName = "SQLPLUS.EXE";
m_StartInfo.CreateNoWindow = true;
m_StartInfo.UseShellExecute = false;
m_StartInfo.Arguments = String.Format("{0}\"{1}\" \"{2}\"", connectionString, sqlfile, sqlLogFileName);
m_Process = Process.Start(m_StartInfo);
Other code.....`
It works fine and the sqlplus log is created fine at sqlLogFileName location. However if the sqlLogFileName has spaces in between (say like "C:\My Application\log.txt"), then the log file is not created, instead gives the error SP2-0768 Illegal SPOOL command on SQL Plus window
Any suggestion how to resolve this? I am using Oracle 11GR2
You just have to surround your file name with double quotes.
Something like:
spool "Test with spaces.txt"
Or in your case with a parameter:
SPOOL "&1"
I think is best not to use spaces though, as #tvCa explained.
Side Note:
What StarPilot is refering to, I believe, is about the redirect a command output to a file, and that is why it didn't work when you tried to use it.
For example in command prompt you would write:
dir > dir.txt
And that saves the output of dir inside dir.txt.
Oracle software is designed to be used with directories not having whitespaces (which is an accepted standard in Linux/Unix, even though technically you can do otherwise). On Windows, things are different, but the Oracle software has the same idea : it does not like whitespaces. So, the fix is clear : spool to a directory without whitespaces. This is advice, anybody is free to take or not.

Not able to see the final result after the Reduce function got executed using Windows Azure Storage in MapReduce

I am using c#.net for writing the map and reduce function.I have basically followed the example being given here
Final command
Hadoop jar hadoop-streaming.jar -files "hdfs:///example/apps/map.exe,hdfs:///example/apps/reduce.exe" -input "/example/apps/data.csv" -output "/example/apps/output.txt" -mapper "map.exe" -reducer "reduce.exe"
The Job ran successfully
Now from the Interactive JS mode, if I write
js> #cat /example/apps/output.txt
cat: File does not exist: /example/apps/output.txt
Where as :
js> #ls /example/apps/output.txt
Found 3 items
-rw-r--r-- 3 xxxx supergroup 0 2013-02-22 10:23 /example/apps/output.txt/_SUCCESS
drwxr-xr-x - xxxx supergroup 0 2013-02-22 10:22 /example/apps/output.txt/_logs
-rw-r--r-- 3 xxxx supergroup 0 2013-02-22 10:23 /example/apps/output.txt/part-00000
What is the mistake I am making and how can I see the output?
The -output flag specifies an output folder, not a file. Since there can be multiple reducers, each one will produce a file in this folder.
In this case, you have one reducer, and it produced one file: part-00000. If there were more reducers, they would be named part-00001, part-00002, etc.
The command cat /example/apps/output.txt/part-00000 will display your output. In the future, don't name your output folders something.txt, as that will just confuse you and others :)

Categories