2016-11-04 1 views
1

ich einen Bash-Skript, das auf einmal mehr laufenden Instanzen ermöglicht. Es gibt jedoch eine sqlplus-Verbindung zu einer Oracle-Datenbank, um einen Wert abzurufen. Wenn dieser Wert von mehreren Bash-Skript-Instanzen gleichzeitig abgerufen wird, können sie denselben Wert abrufen, da die zweite Instanz bereits während der Verarbeitung der ersten Instanz die 'alten Daten' überprüft.Bash Linux Kraft mehr Instanzen für die Ausführung von sqlplus Befehl warten zu beenden

Ich kann nur von zwei Option denken, die durch eine PIDFILE die Funktion blockiert. Nachteil ist, dass wenn der Benutzer den Vorgang abbricht, bevor das Pidfile entfernt wird, wird es Probleme verursachen. Ein anderes ist das Sperren des gesamten Skripts basierend auf dem Deklarieren von maximalen Prozessen, die mit gezählt werden. Dies würde jedoch das gesamte Skript und nicht nur den Datenbankbereich sperren.

Also gibt es vielleicht eine andere Option? Ist diese sqlplus-Verbindung zur Datenbank irgendwie zu erfassen, so kann ich die mehreren laufenden Instanzen in Pause setzen, während diese Funktion von einer der Instanzen ausgeführt wird?

Antwort

1

Sie könnten einen eindeutigen Wert in einer tmp-Datei (/tmp/pidfile für dieses Beispiel) verwenden und ihn bei Abbruch oder Abschluss des Skripts zurücksetzen.

Update: Dies scheint solide, siehe Tests unten.

#!/bin/bash 


bashpid="$$"      # Records PID of script. Unused so far 
pidfile=/tmp/pidfile    # pidfile var 
pidlimit=2      # pidlimit 

cleanup() {      # cleanup operations 
     exit 
    } 

pidreset() {     # trap operations (if reqd) 
     pkill -a -P "$bashpid" 
     kill -9 0 
    } 

trap "pidreset" SIGINT   # trap (if reqd) 


countpid() {     # This is the true PID count, only called 
           # Once allowed in the database block 
           # This includes self instance 

    ps aux | grep "$(basename $0)" | grep -v grep > $pidfile 

} 

countloop() {     # This counts PID while waiting for a spot 
           # (-1 decrement since self is included but 
           # not yet granted access to database block) 
    echo "((("$(ps aux | grep "$(basename $0)" | grep -v grep | wc -l)") - 1))" | bc > $pidfile 

} 
databasecall() {    # The database script calls 

    touch $pidfile 
    pidcount="$(cat $pidfile | wc -l)" 
    until [[ "$pidcount" -le "$pidlimit" ]]; do 
     echo "too many processes" 
     countloop 
     pidcount="$(cat $pidfile | wc -l)" 
     sleep 5 
    done 

    # ================ Start of Database access Code ================ 
    # Go ahead and do database stuff 
    # Write this script into the pidfile incrementing its count also 

    countpid 
    pidcount="$(cat $pidfile | wc -l)" 
    echo "We're in" 
    echo "Scriptcount: $pidcount (Including this one)" 
    sleep 5 
    cleanup 
    # return/whatever 
    # ================ End of Database access Code ================ 

} 



echo "Main script block"   # Main script outside of Database block 
sleep .1 


databasecall      # Call database function 


cleanup       # Call to housekeeping 

Tests

Es funktioniert gut, aber setzt man mehr als pidlimit am Laufen, obwohl ich nicht sicher bin, wo dies auftritt oder wenn es noch mein Testszenario.

 
bash>echo "imrunning & sleep .5 ; imrunning & sleep .5 ; imrunning & sleep .5 ; imrunning & sleep .5 ; imrunning" > /tmp/initrunning ; chmod +x /tmp/initrunning 
bash>/tmp/./initrunning 
Main script block 
We're in 
Scriptcount:  1 (Including this one) 
Main script block 
We're in 
Scriptcount:  2 (Including this one) 
Main script block 
too many processes 
Main script block 
too many processes 
Main script block 
too many processes 
We're in 
Scriptcount:  3 (Including this one) 
We're in 
Scriptcount:  3 (Including this one) 
We're in 
Scriptcount:  3 (Including this one) 
bash

+0

dieses Gut, dass mein Skript nicht haha ​​jeden einfacher. Ziemlich viel umständlich im Vergleich zum Sperren des gesamten Skripts, aber ich denke, es funktioniert. Ich werde etwas Zeit brauchen, um all das zu testen und mein Skript anzupassen. Es gibt also nur eine andere Option, die ich danach gelernt habe (die ich aber auch noch nicht versucht habe); ist ein Schema-Benutzer, der nur 1 Verbindung erlaubt. Wie auch immer, danke für Ihren Code, Zeit und Mühe! :) –

+0

@IvanM Ich höre dich! Ich habe mich mehr auf die Möglichkeit konzentriert, einen Teil des Skripts zu sperren, da mir anfangs nicht klar war, dass Sie versuchen, genau eine Verbindung mit der Datenbank zu sperren. Es gibt viele Unbekannte an meinem Ende, aber ein paar Gedanken .., beeinflusst der Parameter SESSIONS_PER_USER Lesevorgänge? Wenn Sie versuchen, das Lesen vollständig einzuschränken; Abhängig von den Leistungsanforderungen können Sie 'lsof -t/path/to/db.sql' verwenden, um den physischen Zugriff auf die Datei zu erkennen. – hmedia1

+0

@IvanM Wie für den Abbruch der Operation .. um die Situation "Benutzer abbrechen" zu verringern, können Sie die Sperrdatei im Abschnitt cleanup() entfernen/überprüfen/bereinigen. Es ist Templates, um eine Strg + C abzufangen, aber Sie könnten jedes Ereignis zuweisen, das vom Endbenutzer stammt. – hmedia1

Verwandte Themen