kopia lustrzana https://github.com/cyoung/stratux
Added graceful shutdown for SQLite logging
rodzic
2dd8a14d62
commit
24a6da3da9
|
@ -43,6 +43,10 @@ type StratuxStartup struct {
|
||||||
Fill string
|
Fill string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dataLogStarted bool
|
||||||
|
var dataLogReadyToWrite bool
|
||||||
|
|
||||||
|
//var dataLogInShutdown bool
|
||||||
var stratuxStartupID int64
|
var stratuxStartupID int64
|
||||||
var dataLogTimestamps []StratuxTimestamp
|
var dataLogTimestamps []StratuxTimestamp
|
||||||
var dataLogCurTimestamp int64 // Current timestamp bucket. This is an index on dataLogTimestamps which is not necessarily the db id.
|
var dataLogCurTimestamp int64 // Current timestamp bucket. This is an index on dataLogTimestamps which is not necessarily the db id.
|
||||||
|
@ -350,11 +354,13 @@ type DataLogRow struct {
|
||||||
|
|
||||||
var dataLogChan chan DataLogRow
|
var dataLogChan chan DataLogRow
|
||||||
var shutdownDataLog chan bool
|
var shutdownDataLog chan bool
|
||||||
|
var shutdownDataLogWriter chan bool
|
||||||
|
|
||||||
var dataLogWriteChan chan DataLogRow
|
var dataLogWriteChan chan DataLogRow
|
||||||
|
|
||||||
func dataLogWriter(db *sql.DB) {
|
func dataLogWriter(db *sql.DB) {
|
||||||
dataLogWriteChan = make(chan DataLogRow, 10240)
|
dataLogWriteChan = make(chan DataLogRow, 10240)
|
||||||
|
shutdownDataLogWriter = make(chan bool)
|
||||||
// The write queue. As data comes in via dataLogChan, it is timestamped and stored.
|
// The write queue. As data comes in via dataLogChan, it is timestamped and stored.
|
||||||
// When writeTicker comes up, the queue is emptied.
|
// When writeTicker comes up, the queue is emptied.
|
||||||
writeTicker := time.NewTicker(10 * time.Second)
|
writeTicker := time.NewTicker(10 * time.Second)
|
||||||
|
@ -363,6 +369,7 @@ func dataLogWriter(db *sql.DB) {
|
||||||
select {
|
select {
|
||||||
case r := <-dataLogWriteChan:
|
case r := <-dataLogWriteChan:
|
||||||
// Accept timestamped row.
|
// Accept timestamped row.
|
||||||
|
//log.Printf("Accepting timestamped row from dataLogWriteChan\n")
|
||||||
rowsQueuedForWrite = append(rowsQueuedForWrite, r)
|
rowsQueuedForWrite = append(rowsQueuedForWrite, r)
|
||||||
case <-writeTicker.C:
|
case <-writeTicker.C:
|
||||||
// for i := 0; i < 1000; i++ {
|
// for i := 0; i < 1000; i++ {
|
||||||
|
@ -370,9 +377,9 @@ func dataLogWriter(db *sql.DB) {
|
||||||
// }
|
// }
|
||||||
timeStart := stratuxClock.Time
|
timeStart := stratuxClock.Time
|
||||||
nRows := len(rowsQueuedForWrite)
|
nRows := len(rowsQueuedForWrite)
|
||||||
if globalSettings.DEBUG {
|
//if globalSettings.DEBUG {
|
||||||
log.Printf("Writing %d rows\n", nRows)
|
log.Printf("Writing %d rows\n", nRows)
|
||||||
}
|
//}
|
||||||
// Write the buffered rows. This will block while it is writing.
|
// Write the buffered rows. This will block while it is writing.
|
||||||
// Save the names of the tables affected so that we can run bulkInsert() on after the insertData() calls.
|
// Save the names of the tables affected so that we can run bulkInsert() on after the insertData() calls.
|
||||||
tblsAffected := make(map[string]bool)
|
tblsAffected := make(map[string]bool)
|
||||||
|
@ -394,18 +401,26 @@ func dataLogWriter(db *sql.DB) {
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
rowsQueuedForWrite = make([]DataLogRow, 0) // Zero the queue.
|
rowsQueuedForWrite = make([]DataLogRow, 0) // Zero the queue.
|
||||||
timeElapsed := stratuxClock.Since(timeStart)
|
timeElapsed := stratuxClock.Since(timeStart)
|
||||||
if globalSettings.DEBUG {
|
//if globalSettings.DEBUG {
|
||||||
rowsPerSecond := float64(nRows) / float64(timeElapsed.Seconds())
|
rowsPerSecond := float64(nRows) / float64(timeElapsed.Seconds())
|
||||||
log.Printf("Writing finished. %d rows in %.2f seconds (%.1f rows per second).\n", nRows, float64(timeElapsed.Seconds()), rowsPerSecond)
|
log.Printf("Writing finished. %d rows in %.2f seconds (%.1f rows per second).\n", nRows, float64(timeElapsed.Seconds()), rowsPerSecond)
|
||||||
}
|
//}
|
||||||
if timeElapsed.Seconds() > 10.0 {
|
if timeElapsed.Seconds() > 10.0 {
|
||||||
log.Printf("WARNING! SQLite logging is behind. Last write took %.1f seconds.\n", float64(timeElapsed.Seconds()))
|
log.Printf("WARNING! SQLite logging is behind. Last write took %.1f seconds.\n", float64(timeElapsed.Seconds()))
|
||||||
}
|
}
|
||||||
|
case <-shutdownDataLogWriter: // Received a message on the channel (anything). Graceful shutdown (defer statement).
|
||||||
|
log.Printf("dataLogWriter() received shutdown message with len(dataLogWriteChan) = %d and rowsQueuedForWrite = %d\n", len(dataLogWriteChan), len(rowsQueuedForWrite))
|
||||||
|
shutdownDataLog <- true
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf("dataLogWriter() shutting down\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataLog() {
|
func dataLog() {
|
||||||
|
dataLogStarted = true
|
||||||
|
//dataLogInShutdown = false
|
||||||
|
log.Printf("dataLog started\n")
|
||||||
dataLogChan = make(chan DataLogRow, 10240)
|
dataLogChan = make(chan DataLogRow, 10240)
|
||||||
shutdownDataLog = make(chan bool)
|
shutdownDataLog = make(chan bool)
|
||||||
dataLogTimestamps = make([]StratuxTimestamp, 0)
|
dataLogTimestamps = make([]StratuxTimestamp, 0)
|
||||||
|
@ -430,7 +445,12 @@ func dataLog() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("sql.Open(): %s\n", err.Error())
|
log.Printf("sql.Open(): %s\n", err.Error())
|
||||||
}
|
}
|
||||||
defer db.Close()
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
dataLogStarted = false
|
||||||
|
log.Printf("dataLog() dB is now closed\n")
|
||||||
|
}()
|
||||||
|
|
||||||
_, err = db.Exec("PRAGMA journal_mode=WAL")
|
_, err = db.Exec("PRAGMA journal_mode=WAL")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -441,6 +461,7 @@ func dataLog() {
|
||||||
log.Printf("db.Exec('PRAGMA journal_mode=WAL') err: %s\n", err.Error())
|
log.Printf("db.Exec('PRAGMA journal_mode=WAL') err: %s\n", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("Starting dataLogWriter\n")
|
||||||
go dataLogWriter(db)
|
go dataLogWriter(db)
|
||||||
|
|
||||||
// Do we need to create the database?
|
// Do we need to create the database?
|
||||||
|
@ -459,6 +480,8 @@ func dataLog() {
|
||||||
// The first entry to be created is the "startup" entry.
|
// The first entry to be created is the "startup" entry.
|
||||||
stratuxStartupID = insertData(StratuxStartup{}, "startup", db, 0)
|
stratuxStartupID = insertData(StratuxStartup{}, "startup", db, 0)
|
||||||
|
|
||||||
|
dataLogReadyToWrite = true
|
||||||
|
log.Printf("Entering dataLog read loop\n")
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case r := <-dataLogChan:
|
case r := <-dataLogChan:
|
||||||
|
@ -470,9 +493,12 @@ func dataLog() {
|
||||||
// Queue it for the scheduled write.
|
// Queue it for the scheduled write.
|
||||||
dataLogWriteChan <- r
|
dataLogWriteChan <- r
|
||||||
case <-shutdownDataLog: // Received a message on the channel (anything). Graceful shutdown (defer statement).
|
case <-shutdownDataLog: // Received a message on the channel (anything). Graceful shutdown (defer statement).
|
||||||
|
//dataLogStarted = false // moved to defer statement
|
||||||
|
log.Printf("dataLog() received shutdown message\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf("dataLog() shutting down\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -496,49 +522,88 @@ func setDataLogTimeWithGPS(sit SituationData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func logSituation() {
|
func logSituation() {
|
||||||
if globalSettings.ReplayLog {
|
if globalSettings.ReplayLog && dataLogReadyToWrite {
|
||||||
dataLogChan <- DataLogRow{tbl: "mySituation", data: mySituation}
|
dataLogChan <- DataLogRow{tbl: "mySituation", data: mySituation}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func logStatus() {
|
func logStatus() {
|
||||||
if globalSettings.ReplayLog {
|
if globalSettings.ReplayLog && dataLogReadyToWrite {
|
||||||
dataLogChan <- DataLogRow{tbl: "status", data: globalStatus}
|
dataLogChan <- DataLogRow{tbl: "status", data: globalStatus}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func logSettings() {
|
func logSettings() {
|
||||||
if globalSettings.ReplayLog {
|
if globalSettings.ReplayLog && dataLogReadyToWrite {
|
||||||
dataLogChan <- DataLogRow{tbl: "settings", data: globalSettings}
|
dataLogChan <- DataLogRow{tbl: "settings", data: globalSettings}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func logTraffic(ti TrafficInfo) {
|
func logTraffic(ti TrafficInfo) {
|
||||||
if globalSettings.ReplayLog {
|
if globalSettings.ReplayLog && dataLogReadyToWrite {
|
||||||
dataLogChan <- DataLogRow{tbl: "traffic", data: ti}
|
dataLogChan <- DataLogRow{tbl: "traffic", data: ti}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func logMsg(m msg) {
|
func logMsg(m msg) {
|
||||||
if globalSettings.ReplayLog {
|
if globalSettings.ReplayLog && dataLogReadyToWrite {
|
||||||
dataLogChan <- DataLogRow{tbl: "messages", data: m}
|
dataLogChan <- DataLogRow{tbl: "messages", data: m}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func logESMsg(m esmsg) {
|
func logESMsg(m esmsg) {
|
||||||
if globalSettings.ReplayLog {
|
if globalSettings.ReplayLog && dataLogReadyToWrite {
|
||||||
dataLogChan <- DataLogRow{tbl: "es_messages", data: m}
|
dataLogChan <- DataLogRow{tbl: "es_messages", data: m}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func logDump1090TermMessage(m Dump1090TermMessage) {
|
func logDump1090TermMessage(m Dump1090TermMessage) {
|
||||||
if globalSettings.DEBUG && globalSettings.ReplayLog {
|
if globalSettings.DEBUG && globalSettings.ReplayLog && dataLogReadyToWrite {
|
||||||
dataLogChan <- DataLogRow{tbl: "dump1090_terminal", data: m}
|
dataLogChan <- DataLogRow{tbl: "dump1090_terminal", data: m}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDataLog() {
|
func initDataLog() {
|
||||||
|
log.Printf("dataLogStarted = %t. dataLogReadyToWrite = %t\n", dataLogStarted, dataLogReadyToWrite) //REMOVE -- DEBUG
|
||||||
insertString = make(map[string]string)
|
insertString = make(map[string]string)
|
||||||
insertBatchIfs = make(map[string][][]interface{})
|
insertBatchIfs = make(map[string][][]interface{})
|
||||||
go dataLog()
|
if globalSettings.ReplayLog {
|
||||||
|
go dataLog()
|
||||||
|
}
|
||||||
|
go dataLogWatchdog()
|
||||||
|
log.Printf("initDataLog complete.\n") //REMOVE -- DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watchdog function to control startup / shutdown of data logging subsystem
|
||||||
|
|
||||||
|
func dataLogWatchdog() {
|
||||||
|
for {
|
||||||
|
log.Printf("Watchdog loop begins. dataLogStarted = %t\n", dataLogStarted)
|
||||||
|
if !dataLogStarted && globalSettings.ReplayLog { // case 1: sqlite logging isn't running, and we want to start it
|
||||||
|
log.Printf("Watchdog wants to START logging.\n")
|
||||||
|
go dataLog()
|
||||||
|
} else if dataLogStarted && !globalSettings.ReplayLog { // case 2: sqlite logging is running, and we want to shut it down
|
||||||
|
log.Printf("Watchdog wants to STOP logging.\n")
|
||||||
|
closeDataLog()
|
||||||
|
}
|
||||||
|
log.Printf("Watchdog iterated.\n") //REMOVE -- DEBUG
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
log.Printf("Watchdog sleep over.\n") //REMOVE -- DEBUG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler for graceful shutdown of data logging goroutines. Intended to be called by dataLogWatchdog() and gracefulShutdown()
|
||||||
|
|
||||||
|
func closeDataLog() {
|
||||||
|
log.Printf("closeDataLog(): dataLogStarted = %t\n", dataLogStarted) //REMOVE -- DEBUG
|
||||||
|
dataLogReadyToWrite = false // prevent any new messages from being sent down the channels
|
||||||
|
log.Printf("Shutting down SQLite data log\n")
|
||||||
|
shutdownDataLogWriter <- true
|
||||||
|
log.Printf("Waiting for signal from dataLog()") //REMOVE -- DEBUG
|
||||||
|
for dataLogStarted {
|
||||||
|
log.Printf("closeDataLog(): dataLogStarted = %t\n", dataLogStarted) //REMOVE -- DEBUG
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
}
|
||||||
|
log.Printf("closeDataLog(): Finished wait. dataLogStarted = %t\n", dataLogStarted) //REMOVE -- DEBUG
|
||||||
|
log.Printf("closeDataLog() complete")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1191,8 +1191,14 @@ func gracefulShutdown() {
|
||||||
// Shut down SDRs.
|
// Shut down SDRs.
|
||||||
sdrKill()
|
sdrKill()
|
||||||
//TODO: Any other graceful shutdown functions.
|
//TODO: Any other graceful shutdown functions.
|
||||||
|
|
||||||
// Shut down data logging.
|
// Shut down data logging.
|
||||||
shutdownDataLog <- true
|
if dataLogStarted {
|
||||||
|
closeDataLog()
|
||||||
|
//log.Printf("Waiting for log file to close\n")
|
||||||
|
//time.Sleep(3*time.Second) // FIXME
|
||||||
|
}
|
||||||
|
// shutdownDataLog <- true
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue