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.

This commit is contained in:
Sascha L. Teichmann 2014-09-20 12:28:38 +02:00
parent e899b13889
commit 3e4c1aa2d9

View File

@ -10,7 +10,9 @@ import (
"image/color" "image/color"
"log" "log"
"net/http" "net/http"
"os"
"path/filepath" "path/filepath"
"strconv"
"sync" "sync"
"bitbucket.org/s_l_teichmann/mtredisalize/common" "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 { if client, err = common.NewRedisClient("tcp", tu.redisAddress); err != nil {
return return
} }
btc := NewBaseTileCreator(client, tu.colors, baseDir) btc := NewBaseTileCreator(client, tu.colors, baseDir, true)
go btc.run(jobs) go btc.run(jobs)
} }
@ -137,17 +139,22 @@ type BaseTileCreator struct {
renderer *common.Renderer renderer *common.Renderer
yOrder *common.YOrder yOrder *common.YOrder
baseDir string baseDir string
update bool
} }
func NewBaseTileCreator(client *common.RedisClient, func NewBaseTileCreator(
colors *common.Colors, baseDir string) *BaseTileCreator { client *common.RedisClient,
colors *common.Colors,
baseDir string,
update bool) *BaseTileCreator {
renderer := common.NewRenderer(tileWidth, tileHeight) renderer := common.NewRenderer(tileWidth, tileHeight)
return &BaseTileCreator{ return &BaseTileCreator{
client: client, client: client,
colors: colors, colors: colors,
baseDir: baseDir,
renderer: renderer, renderer: renderer,
yOrder: common.NewYOrder(renderer, yOrderCapacity)} yOrder: common.NewYOrder(renderer, yOrderCapacity),
baseDir: baseDir,
update: update}
} }
func (btc *BaseTileCreator) run(jobs chan xz) { 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, 16, 16, (tileWidth-2)*16, (tileHeight-2)*16,
btc.colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}) 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)) path := filepath.Join(btc.baseDir, strconv.Itoa(i), fmt.Sprintf("%d.png", j))
log.Printf("file path: %s", path)
log.Printf("Writing (%d, %d) (%d, %d)", i, j, x, z) log.Printf("Writing (%d, %d) to file %s", x, z, path)
if !btc.update {
return common.SaveAsPNG(path, image) 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)
} }