mtwebmapper: First version of pyramid tile updater. Needs testing.

This commit is contained in:
Sascha L. Teichmann
2014-09-21 17:30:19 +02:00
parent 4e80236e26
commit c428756beb
4 changed files with 139 additions and 34 deletions

View File

@ -8,7 +8,6 @@ import (
"fmt"
"image/color"
"log"
"os"
"path/filepath"
"strconv"
)
@ -129,17 +128,5 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) error {
return 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 := SaveAsPNG(pathTmp, image); err != nil {
return err
}
return os.Rename(pathTmp, path)
return SaveAsPNGAtomic(path, image)
}

View File

@ -6,12 +6,35 @@ package common
import (
"bufio"
"errors"
"image"
"image/png"
"log"
"os"
"strconv"
"sync"
"time"
)
var rand uint32
var randmu sync.Mutex
func reseed() uint32 {
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}
func nextSuffix() string {
randmu.Lock()
r := rand
if r == 0 {
r = reseed()
}
r = r*1664525 + 1013904223 // constants from Numerical Recipes
rand = r
randmu.Unlock()
return strconv.Itoa(int(1e9 + r%1e9))[1:]
}
func SaveAsPNG(path string, img image.Image) (err error) {
var file *os.File
if file, err = os.Create(path); err != nil {
@ -24,6 +47,38 @@ func SaveAsPNG(path string, img image.Image) (err error) {
return
}
func tmpName(tmpl string) (string, error) {
tmpPre := tmpl + ".tmp"
nconflict := 0
for i := 0; i < 10000; i++ {
tmp := tmpPre + nextSuffix()
if _, err := os.Stat(tmp); err != nil {
if os.IsNotExist(err) {
return tmp, nil
}
return "", err
}
if nconflict++; nconflict > 10 {
nconflict = 0
rand = reseed()
}
}
return "", errors.New("Cannot create temp name")
}
func SaveAsPNGAtomic(path string, img image.Image) (err error) {
var tmpPath string
if tmpPath, err = tmpName(path); err != nil {
return
}
// Still a bit racy
if err = SaveAsPNG(tmpPath, img); err != nil {
return
}
return os.Rename(tmpPath, path)
}
func LoadPNG(path string) image.Image {
var err error
var file *os.File