mirror of
				https://bitbucket.org/s_l_teichmann/mtsatellite
				synced 2025-11-04 09:55:34 +01:00 
			
		
		
		
	Added naive BigMin interleaved implementation for interleaved spatial query.
This commit is contained in:
		@@ -21,6 +21,10 @@ type (
 | 
			
		||||
		X, Y, Z int16
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Cuboid struct {
 | 
			
		||||
		P1, P2 Coord
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	KeyTransformer func(int64) int64
 | 
			
		||||
	KeyEncoder     func(int64) ([]byte, error)
 | 
			
		||||
	KeyDecoder     func([]byte) (int64, error)
 | 
			
		||||
@@ -29,6 +33,12 @@ type (
 | 
			
		||||
	KeyJoiner      func(Coord) int64
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (cub Cuboid) Contains(c Coord) bool {
 | 
			
		||||
	return c.X >= cub.P1.X && c.X <= cub.P2.X &&
 | 
			
		||||
		c.Y >= cub.P1.Y && c.Y <= cub.P2.Y &&
 | 
			
		||||
		c.Z >= cub.P1.Z && c.Z <= cub.P2.Z
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c Coord) String() string {
 | 
			
		||||
	return fmt.Sprintf("(%d, %d, %d)", c.X, c.Y, c.Z)
 | 
			
		||||
}
 | 
			
		||||
@@ -204,3 +214,23 @@ func TranscodeInterleavedToPlain(key []byte) ([]byte, error) {
 | 
			
		||||
		return EncodeStringToBytes(TransformInterleavedToPlain(pos))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// For correctness checks only.
 | 
			
		||||
func NaiveBigMin(minz, maxz, zcode int64) int64 {
 | 
			
		||||
	c1, c2 := InterleavedToCoord(minz), InterleavedToCoord(maxz)
 | 
			
		||||
 | 
			
		||||
	cand := minz
 | 
			
		||||
 | 
			
		||||
	for x := c1.X; x <= c2.X; x++ {
 | 
			
		||||
		for y := c1.Y; y <= c2.Y; y++ {
 | 
			
		||||
			for z := c1.Z; z <= c2.Z; z++ {
 | 
			
		||||
				z := CoordToInterleaved(Coord{X: x, Y: y, Z: z})
 | 
			
		||||
				if z > zcode && z < cand {
 | 
			
		||||
					cand = z
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cand
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										88
									
								
								sqlite.go
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								sqlite.go
									
									
									
									
									
								
							@@ -23,7 +23,7 @@ const (
 | 
			
		||||
	insertSql = "INSERT INTO blocks (pos, data) VALUES (?, ?)"
 | 
			
		||||
	countSql  = "SELECT count(*) FROM blocks"
 | 
			
		||||
	keysSql   = "SELECT pos FROM blocks"
 | 
			
		||||
	rangeSql  = "SELECT pos, data FROM blocks WHERE pos BETWEEN ? AND ?"
 | 
			
		||||
	rangeSql  = "SELECT pos, data FROM blocks WHERE pos BETWEEN ? AND ? ORDER BY pos"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SqliteBackend struct {
 | 
			
		||||
@@ -283,15 +283,13 @@ func (ss *SqliteSession) AllKeys(hash []byte, done chan struct{}) (keys chan []b
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ss *SqliteSession) SpatialQuery(hash, first, second []byte, done chan struct{}) (blocks chan Block, err error) {
 | 
			
		||||
func (ss *SqliteSession) SpatialQuery(hash, first, second []byte, done chan struct{}) (chan Block, error) {
 | 
			
		||||
 | 
			
		||||
	// No implementation for the interleaved case, yet.
 | 
			
		||||
	if ss.backend.interleaved {
 | 
			
		||||
		err = ErrNotImplemented
 | 
			
		||||
		return
 | 
			
		||||
		return ss.interleavedSpatialQuery(first, second, done)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ss.PlainSpatialQuery(first, second, done)
 | 
			
		||||
	return ss.plainSpatialQuery(first, second, done)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func order(a, b int64) (int64, int64) {
 | 
			
		||||
@@ -301,7 +299,79 @@ func order(a, b int64) (int64, int64) {
 | 
			
		||||
	return b, a
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ss *SqliteSession) PlainSpatialQuery(first, second []byte, done chan struct{}) (blocks chan Block, err error) {
 | 
			
		||||
func (ss *SqliteSession) interleavedSpatialQuery(first, second []byte, done chan struct{}) (blocks chan Block, err error) {
 | 
			
		||||
	var (
 | 
			
		||||
		firstKey  int64
 | 
			
		||||
		secondKey int64
 | 
			
		||||
	)
 | 
			
		||||
	if firstKey, err = common.DecodeStringFromBytes(first); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if secondKey, err = common.DecodeStringFromBytes(second); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c1 := common.PlainToCoord(firstKey)
 | 
			
		||||
	c2 := common.PlainToCoord(secondKey)
 | 
			
		||||
	c1, c2 = common.MinCoord(c1, c2), common.MaxCoord(c1, c2)
 | 
			
		||||
 | 
			
		||||
	blocks = make(chan Block)
 | 
			
		||||
 | 
			
		||||
	globalLock.RLock()
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		defer close(blocks)
 | 
			
		||||
		defer globalLock.RUnlock()
 | 
			
		||||
		zmin, zmax := common.CoordToInterleaved(c1), common.CoordToInterleaved(c2)
 | 
			
		||||
		// Should not be necessary.
 | 
			
		||||
		zmin, zmax = order(zmin, zmax)
 | 
			
		||||
		cub := common.Cuboid{P1: c1, P2: c2}
 | 
			
		||||
		rangeStmt := ss.txStmt(ss.backend.rangeStmt)
 | 
			
		||||
	OUTER:
 | 
			
		||||
		for {
 | 
			
		||||
			var (
 | 
			
		||||
				err  error
 | 
			
		||||
				rows *sql.Rows
 | 
			
		||||
			)
 | 
			
		||||
			if rows, err = rangeStmt.Query(zmin, zmax); err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			for rows.Next() {
 | 
			
		||||
				var zcode int64
 | 
			
		||||
				var data []byte
 | 
			
		||||
				if err = rows.Scan(&zcode, &data); err != nil {
 | 
			
		||||
					log.Printf("Error in range query: %s", err)
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
				c := common.InterleavedToCoord(zcode)
 | 
			
		||||
				if cub.Contains(c) {
 | 
			
		||||
					var encodedKey []byte
 | 
			
		||||
					if encodedKey, err = common.EncodeStringToBytes(common.CoordToPlain(c)); err != nil {
 | 
			
		||||
						log.Printf("Key encoding failed: %s", err)
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
					select {
 | 
			
		||||
					case blocks <- Block{Key: encodedKey, Data: data}:
 | 
			
		||||
					case <-done:
 | 
			
		||||
						rows.Close()
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
				} else { // Left the cuboid
 | 
			
		||||
					rows.Close()
 | 
			
		||||
					zmin = common.NaiveBigMin(zmin, zmax, zcode)
 | 
			
		||||
					continue OUTER
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if err = rows.Err(); err != nil {
 | 
			
		||||
				log.Printf("Error in range query: %s", err)
 | 
			
		||||
			}
 | 
			
		||||
			rows.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ss *SqliteSession) plainSpatialQuery(first, second []byte, done chan struct{}) (blocks chan Block, err error) {
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		firstKey  int64
 | 
			
		||||
@@ -317,10 +387,10 @@ func (ss *SqliteSession) PlainSpatialQuery(first, second []byte, done chan struc
 | 
			
		||||
	c2 := common.PlainToCoord(secondKey)
 | 
			
		||||
	c1, c2 = common.MinCoord(c1, c2), common.MaxCoord(c1, c2)
 | 
			
		||||
 | 
			
		||||
	globalLock.RLock()
 | 
			
		||||
 | 
			
		||||
	blocks = make(chan Block)
 | 
			
		||||
 | 
			
		||||
	globalLock.RLock()
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		defer globalLock.RUnlock()
 | 
			
		||||
		defer close(blocks)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user