Open milicagnjatovic opened 9 months ago
Skripti se prosleđuje fajl u formatu:
taskid_1
quey_1
taskid_2
quey_2
...
Izvrši se konektovanje na bazu podataka.
Čitaju se dve po dve linije i izvršava naredno:
db2 "$query" | sed '/^$/d' > "results/$task_id"
Važno je da se svi upiti redom izvršavaju sa jednom konekcijom.
Komanda timeout t command
prekida izvršavanje command nakom t sekundi. Ukoliko se izvršvanje završilo ranije nema čekanja.
Timeout će pokrenuti novi child proces koji nema uspostavljenu konekciju na bazu pa jednostavno izvršavanje nije moguće:
timeout 5s db2 "$query" | sed '/^$/d' > "results/$task_id"
Mogli bi ulančati komandu za povezivanje na bazu u timeout, ali kako je ovde ideja jednom konekcijom izvršiti sve upite iskoristićemo narednu alternativu, a timeout će biti iskorišćen za proveru efikasnoti studnetskog koda.
db2 "$query" | sed '/^$/d' > "results/$task_id" & # Proces za izvršavanje upita ide u pozadinu i ne blokira dalje izvršavanje
pid=$! # id prethodnog procesa u pozadini
# petlja koja proverava da li je upit izvršen na svake 0.02 sekunde
for ((i=0; i<200; i++)); do
sleep 0.02s
if ! ps -p $pid > /dev/null; then # provera da li je proces gotov
skip=false
break
fi
done
if $skip; then # ukoliko proces nije završen nakon datog vremena gasi se i javalj poruka da je prekoračeno vremensko ograničenje
kill $pid
echo "$task_id | Time limit exceeded"
continue
fi
Na osnovu vremena izvršavanja svakog upita bez ograničenja su dobijene naredne vrednosti:
Pri izboru vremenskog koraka je razmotreno vreme potrebno za generisanje 99 upita (od čega 10 sa ispita): | Vremenski korak | Vreme izvršavanja | Komentar |
---|---|---|---|
nema | 12.97s | Nije opcija jer može da blokira sistem ako se pošalje upit koji se predugo izvršava | |
1s | 104.53s | Predug opseg, većina upita će se izvršiti dosta pre prve provere | |
0.5s | 57.60s | Vreme izvršavanja je skoro 6 puta duže nego bez ograničenja, vreme čekanja je predugo | |
0.2s | 30.98s | ||
0.1s | 21.89s | ||
0.05s | 16.41s | Na osnovu medijane bi se zaključilo da je ovo idelan granica jer bi se polovina upita izvršila pre prve promene | |
0.03s | 15.16s | ||
0.02s | 14.43s | Najmanje vreme izvršavanja | |
0.01s | 14.46s | Vreme je nešto duže jer se provere izvršavaju previše često |
Ovako dato ograničenje ima smisla ukoliko će vreme koje se provodi u čekanju biti manje od vremena potrebnog za izvršavanje svih koenkcija na bazu.
Još jedna važna napomena je da sa jednom komenkcijom u jednom trenutku može da se izvršava samo jedan upit, pa sleep i izvršavanje upita u pozadini ne daju dobre rezulatet. Izvršavanje koda na takav način ja dalo nepredvidive rezulatet. Prilikom generisanja 12 upita, od kojih se dva izvršavaju sporije, dok se poslednji izvršava brzo (select * iz manje tabele) u tri izvršavanja su dobijeni naredni rezultati:
Još jedno razmatranje bi bilo da li vremenski korak da se menja vremenom, na primer počeni korak 0.05 sekundi, pa da se dalje proverava na 0.01 sekundu.
Na kraju treba imati vidu da se generisanje rezultujućih fajlova neće izvršavati veoma često i da nije prioritet da se izvrši najbrže moguće.
U prethodnom komenataru je razmotrena komanda timeout koja će ovde biti iskorišćena. U procesu koji pokreće timeout je potrebno izvršiti konekciju na bazu podatak:
timeout 5 bash -c "
db2 connect to stud2020 > /dev/null;
db2 "'$query'" | sed '/^$/d' > '$user_path' "
Ovde se javlja problem sa prosleđivanjem argumenata procesu jer je potrebno komande staviti između jednostrukih ili dvostrukih navodnika, dok upiti koriste i jednostruke i dvostruke navodnike. Provera:
echo '-------------'
echo "$query"
echo '-------------'
timeout 5 bash -c "
echo \"$query\"
echo '-------------'
echo '$query'
echo '-------------'
Izlaz:
-------------
SELECT ime || ' ' || prezime "ime i prezime" from da.dosije # navodnici su u redu
-------------
SELECT ime || ' ' || prezime ime i prezime from da.dosije # fale navodnici za ime i prezime
-------------
SELECT ime || || prezime "ime i prezime" from da.dosije # fale navodnici za razmak
-------------
Jedna ideja bi bila da se upit upiše u fajl, pa da timeout proces izvrši iz fajla. Ali onda bi se nepotrebno pravio fajl.
Druga ideja je pravljenje funkcije koja bi se pozivala iz timeout. U tom slučaju je funkciju i argumente potrebno exportovati da bi bili vidljivi u child procesima:
function execute_query() {
db2 connect to stud2020 > /dev/null; # na izlat treba da ide samo poruka o izvršavanju, ne rezultat konekcije
db2 "$query" | sed '/^$/d' > "$user_path"
}
export -f execute_query
export query="$query"
export user_path="$user_path"
# funkcija se izvršava 5 sekundi, ukoliko se ne završi za to vreme prekida se izvršavanje
timeout 5 bash -c "execute_query"
# if last command failed
if [ $? -ne 0 ]; then
echo "User error | Time limit exceeded"
if [ -e "$user_path" ]; then
rm "$user_path"
exit 1
fi
fi
Problem: ograničiti vreme izvršvanja generisanja fajla sa rešenjem i izvršavanja studentskog upita.