From 0c5c733e3c1bc160c7928dc639731b0930122e05 Mon Sep 17 00:00:00 2001 From: Ulf Bjorkengren Date: Mon, 30 Oct 2023 17:13:30 +0100 Subject: [PATCH 1/2] Feeder template updated to support also sqlite statestorage. Signed-off-by: Ulf Bjorkengren --- feeder/feeder-template/feeder.go | 92 +++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/feeder/feeder-template/feeder.go b/feeder/feeder-template/feeder.go index 9db01b6e..bc2b544f 100644 --- a/feeder/feeder-template/feeder.go +++ b/feeder/feeder-template/feeder.go @@ -8,9 +8,11 @@ package main import ( + "database/sql" "encoding/json" "github.com/akamensky/argparse" "github.com/go-redis/redis" + _ "github.com/mattn/go-sqlite3" "github.com/w3c/automotive-viss2/utils" "io/ioutil" "math/rand" @@ -30,6 +32,10 @@ type FeederMap struct { VehicleName string `json:"vehicledata"` } +var redisClient *redis.Client +var dbHandle *sql.DB +var stateDbType string + func readFeederMap(mapFilename string) []FeederMap { var fMap []FeederMap data, err := ioutil.ReadFile(mapFilename) @@ -48,13 +54,12 @@ func readFeederMap(mapFilename string) []FeederMap { func initVSSInterfaceMgr(inputChan chan DomainData, outputChan chan DomainData) { udsChan := make(chan DomainData, 1) - feederClient := initRedisClient() - go initUdsEndpoint(udsChan, feederClient) + go initUdsEndpoint(udsChan) for { select { case outData := <-outputChan: utils.Info.Printf("Data written to statestorage: Name=%s, Value=%s", outData.Name, outData.Value) - status := redisSet(feederClient, outData.Name, outData.Value, utils.GetRfcTime()) + status := statestorageSet(outData.Name, outData.Value, utils.GetRfcTime()) if status != 0 { utils.Error.Printf("initVSSInterfaceMgr():Redis write failed") } @@ -64,26 +69,35 @@ func initVSSInterfaceMgr(inputChan chan DomainData, outputChan chan DomainData) } } -func initRedisClient() *redis.Client { - return redis.NewClient(&redis.Options{ - Network: "unix", - Addr: "/var/tmp/vissv2/redisDB.sock", - Password: "", - DB: 1, - }) -} +func statestorageSet(path string, val string, ts string) int { + switch stateDbType { + case "sqlite": + stmt, err := dbHandle.Prepare("UPDATE VSS_MAP SET c_value=?, c_ts=? WHERE `path`=?") + if err != nil { + utils.Error.Printf("Could not prepare for statestorage updating, err = %s", err) + return -1 + } + defer stmt.Close() -func redisSet(client *redis.Client, path string, val string, ts string) int { - dp := `{"val":"` + val + `", "ts":"` + ts + `"}` - err := client.Set(path, dp, time.Duration(0)).Err() - if err != nil { - utils.Error.Printf("Job failed. Err=%s", err) - return -1 + _, err = stmt.Exec(val, ts, path) + if err != nil { + utils.Error.Printf("Could not update statestorage, err = %s", err) + return -1 + } + return 0 + case "redis": + dp := `{"val":"` + val + `", "ts":"` + ts + `"}` + err := redisClient.Set(path, dp, time.Duration(0)).Err() + if err != nil { + utils.Error.Printf("Job failed. Err=%s", err) + return -1 + } + return 0 } - return 0 + return -1 } -func initUdsEndpoint(udsChan chan DomainData, redisClient *redis.Client) { +func initUdsEndpoint(udsChan chan DomainData) { os.Remove("/var/tmp/vissv2/server-feeder-channel.sock") listener, err := net.Listen("unix", "/var/tmp/vissv2/server-feeder-channel.sock") //the file must be the same as declared in the feeder-registration.json that the service mgr reads if err != nil { @@ -224,14 +238,54 @@ func main() { Required: false, Help: "changes log output level", Default: "info"}) + stateDB := parser.Selector("s", "statestorage", []string{"sqlite", "redis", "none"}, &argparse.Options{Required: false, + Help: "Statestorage must be either sqlite, redis, or none", Default: "redis"}) + dbFile := parser.String("f", "dbfile", &argparse.Options{ + Required: false, + Help: "statestorage database filename", + Default: "../../server/vissv2server/serviceMgr/statestorage.db"}) // Parse input err := parser.Parse(os.Args) if err != nil { utils.Error.Print(parser.Usage(err)) } + stateDbType = *stateDB utils.InitLog("feeder-log.txt", "./logs", *logFile, *logLevel) + switch stateDbType { + case "sqlite": + var dbErr error + if utils.FileExists(*dbFile) { + dbHandle, dbErr = sql.Open("sqlite3", *dbFile) + if dbErr != nil { + utils.Error.Printf("Could not open state storage file = %s, err = %s", *dbFile, dbErr) + os.Exit(1) + } else { + utils.Info.Printf("SQLite state storage initialised.") + } + } else { + utils.Error.Printf("Could not find state storage file = %s", *dbFile) + } + case "redis": + redisClient = redis.NewClient(&redis.Options{ + Network: "unix", + Addr: "/var/tmp/vissv2/redisDB.sock", + Password: "", + DB: 1, + }) + err := redisClient.Ping().Err() + if err != nil { + utils.Error.Printf("Could not initialise redis DB, err = %s", err) + os.Exit(1) + } else { + utils.Info.Printf("Redis state storage initialised.") + } + default: + utils.Error.Printf("Unknown state storage type = %s", stateDbType) + os.Exit(1) + } + vssInputChan := make(chan DomainData, 1) vssOutputChan := make(chan DomainData, 1) vehicleInputChan := make(chan DomainData, 1) From ec98139ee86911d3b8a420272962ddce7e6354df Mon Sep 17 00:00:00 2001 From: Ulf Bjorkengren Date: Tue, 31 Oct 2023 10:58:47 +0100 Subject: [PATCH 2/2] Tutorial update. Signed-off-by: Ulf Bjorkengren --- tutorial/content/build-system/_index.md | 6 ++++++ tutorial/content/feeder/_index.md | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tutorial/content/build-system/_index.md b/tutorial/content/build-system/_index.md index 0d6299ca..3d20dd8b 100644 --- a/tutorial/content/build-system/_index.md +++ b/tutorial/content/build-system/_index.md @@ -40,6 +40,12 @@ After the refactoring of these SwCs into one process with ech actor running as a it became more convenient to build without this script, but it is still [avaliable](https://github.com/w3c/automotive-viss2/blob/master/W3CServer.sh). For more details, see the "Multi-process vs single-process server implementation" chapter in the README. +### Loggging +Logging can be command line configured at startup. +* logging level can be set to either of [trace, debug, info, warn, error, fatal, panic]. +* logging output destination. It can either be written to file, or directed to standard output. +The levels currently used are mainly info, warn, error. Info is appropriate during testing and debugging, while error is appropriate when performance is important. + ### Go modules Go modules are used in multiple places in this project, below follows some commands that may be helpful in managing this. diff --git a/tutorial/content/feeder/_index.md b/tutorial/content/feeder/_index.md index 43d8a70e..f92864ae 100644 --- a/tutorial/content/feeder/_index.md +++ b/tutorial/content/feeder/_index.md @@ -22,9 +22,9 @@ the state storage to find new write requests. * Figure 2. Feeder software architecture version 2 A feeder implementing the 2nd version of the SwA is found at the master branch. -This feeder currently only implements the Redis state storage interface, please see the Datastore chapter for Redis details. +This feeder can be configured to either use an SQLite, or a Redis state storage interface, please see the Datastore chapter for details. -A design for how the polling on the server side can be mitigaed is in the planning stage. +A design for how the polling on the server side can be mitigaed is in the planning stage. It is likely to require an update of the feeder interface. The feeder translation task is divided into a mapping of the signal name, and a possible scaling of the value.