From 3e4c1aa2d9880c716b566e100033f57c625094a1 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Sat, 20 Sep 2014 12:28:38 +0200 Subject: [PATCH] mtwebmapper: To avoid possible races when serving tiles the same time as re-generating them the re-generation write them to temp files and rename them afterwards. --- cmd/mtwebmapper/tilesupdater.go | 40 +++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/cmd/mtwebmapper/tilesupdater.go b/cmd/mtwebmapper/tilesupdater.go index a77745e..ba65080 100644 --- a/cmd/mtwebmapper/tilesupdater.go +++ b/cmd/mtwebmapper/tilesupdater.go @@ -10,7 +10,9 @@ import ( "image/color" "log" "net/http" + "os" "path/filepath" + "strconv" "sync" "bitbucket.org/s_l_teichmann/mtredisalize/common" @@ -107,7 +109,7 @@ func (tu *tileUpdater) doUpdates() (err error) { if client, err = common.NewRedisClient("tcp", tu.redisAddress); err != nil { return } - btc := NewBaseTileCreator(client, tu.colors, baseDir) + btc := NewBaseTileCreator(client, tu.colors, baseDir, true) go btc.run(jobs) } @@ -137,17 +139,22 @@ type BaseTileCreator struct { renderer *common.Renderer yOrder *common.YOrder baseDir string + update bool } -func NewBaseTileCreator(client *common.RedisClient, - colors *common.Colors, baseDir string) *BaseTileCreator { +func NewBaseTileCreator( + client *common.RedisClient, + colors *common.Colors, + baseDir string, + update bool) *BaseTileCreator { renderer := common.NewRenderer(tileWidth, tileHeight) return &BaseTileCreator{ client: client, colors: colors, - baseDir: baseDir, renderer: renderer, - yOrder: common.NewYOrder(renderer, yOrderCapacity)} + yOrder: common.NewYOrder(renderer, yOrderCapacity), + baseDir: baseDir, + update: update} } func (btc *BaseTileCreator) run(jobs chan xz) { @@ -215,10 +222,25 @@ func (btc *BaseTileCreator) createTile(x, z int16, i, j int) error { 16, 16, (tileWidth-2)*16, (tileHeight-2)*16, btc.colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}) - path := filepath.Join(btc.baseDir, fmt.Sprintf("%d", i), fmt.Sprintf("%d.png", j)) - log.Printf("file path: %s", path) + path := filepath.Join(btc.baseDir, strconv.Itoa(i), fmt.Sprintf("%d.png", j)) - log.Printf("Writing (%d, %d) (%d, %d)", i, j, x, z) + log.Printf("Writing (%d, %d) to file %s", x, z, path) - return common.SaveAsPNG(path, image) + if !btc.update { + return common.SaveAsPNG(path, image) + } + + // Try to make creation of update "atomic" by first writing to tmp file + // and rename the tmp file to the original one afterwards. + pathTmp := path + "tmp" + pathTmpPre := pathTmp + tc := 0 + for _, err := os.Stat(pathTmp); err == nil; _, err = os.Stat(pathTmp) { + pathTmp = fmt.Sprintf("%s%d", pathTmpPre, tc) + tc++ + } + if err := common.SaveAsPNG(pathTmp, image); err != nil { + return err + } + return os.Rename(pathTmp, path) }