Skip to content

Commit

Permalink
Create a global set of provider instances (namespaced by app name) to…
Browse files Browse the repository at this point in the history
… track their lifecyeles, thus removing this responsibility from the individual drivers.
  • Loading branch information
jchamberlain committed Sep 18, 2023
1 parent 971a99f commit c0ff399
Show file tree
Hide file tree
Showing 18 changed files with 172 additions and 186 deletions.
2 changes: 1 addition & 1 deletion cmd/internal/register/maps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestMaps(t *testing.T) {
provArr[i] = tc.providers[i]
}

providers, err := register.Providers(provArr, tc.maps)
providers, err := register.Providers(provArr, tc.maps, "default")
if err != nil {
t.Errorf("unexpected err: %v", err)
return
Expand Down
13 changes: 11 additions & 2 deletions cmd/internal/register/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (e ErrProviderTypeInvalid) Error() string {
}

// Providers registers data provider backends
func Providers(providers []dict.Dicter, maps []provider.Map) (map[string]provider.TilerUnion, error) {
func Providers(providers []dict.Dicter, maps []provider.Map, namespace string) (map[string]provider.TilerUnion, error) {
// holder for registered providers
registeredProviders := map[string]provider.TilerUnion{}

Expand Down Expand Up @@ -72,7 +72,7 @@ func Providers(providers []dict.Dicter, maps []provider.Map) (map[string]provide
}

// register the provider
prov, err := provider.For(ptype, p, maps)
prov, err := provider.For(ptype, p, maps, namespace)
if err != nil {
return registeredProviders, err
}
Expand All @@ -84,3 +84,12 @@ func Providers(providers []dict.Dicter, maps []provider.Map) (map[string]provide

return registeredProviders, nil
}

func UnloadProviders(names []string, namespace string) {
for _, name := range names {
err := provider.Remove(name, namespace)
if err != nil {
log.Errorf("Error unloading provider instance %s: %s", name, err)
}
}
}
2 changes: 1 addition & 1 deletion cmd/internal/register/providers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestProviders(t *testing.T) {
provArr[i] = tc.config[i]
}

_, err = register.Providers(provArr, nil)
_, err = register.Providers(provArr, nil, "default")
if tc.expectedErr != nil {
if err.Error() != tc.expectedErr.Error() {
t.Errorf("invalid error. expected: %v, got %v", tc.expectedErr, err.Error())
Expand Down
27 changes: 21 additions & 6 deletions cmd/tegola/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func initConfig(configFile string, cacheRequired bool, logLevel string, logger s
}

// Init providers from the primary config file.
providers, err := initProviders(conf.Providers, conf.Maps)
providers, err := initProviders(conf.Providers, conf.Maps, "default")
if err != nil {
return err
}
Expand Down Expand Up @@ -159,14 +159,14 @@ func initConfig(configFile string, cacheRequired bool, logLevel string, logger s
}

// initProviders translate provider config from a TOML file into usable Provider objects.
func initProviders(providersConfig []env.Dict, maps []provider.Map) (map[string]provider.TilerUnion, error) {
func initProviders(providersConfig []env.Dict, maps []provider.Map, namespace string) (map[string]provider.TilerUnion, error) {
// first convert []env.Map -> []dict.Dicter
provArr := make([]dict.Dicter, len(providersConfig))
for i := range provArr {
provArr[i] = providersConfig[i]
}

providers, err := register.Providers(provArr, conf.Maps)
providers, err := register.Providers(provArr, conf.Maps, namespace)
if err != nil {
return nil, fmt.Errorf("could not register providers: %v", err)
}
Expand Down Expand Up @@ -229,15 +229,15 @@ func watchAppUpdates(ctx context.Context, watcher source.ConfigWatcher) {
// If the new app is named the same as an existing app, first unload the existing one.
if old, exists := apps[app.Key]; exists {
log.Infof("Unloading app %s...", old.Key)
// We need only unload maps, since the providers don't live outside of maps.
register.UnloadMaps(nil, getMapNames(old))
delete(apps, app.Key)
register.UnloadProviders(getProviderNames(old), old.Key)
delete(apps, old.Key)
}

log.Infof("Loading app %s...", app.Key)

// Init new providers
providers, err := initProviders(app.Providers, app.Maps)
providers, err := initProviders(app.Providers, app.Maps, app.Key)
if err != nil {
log.Errorf("Failed initializing providers from %s: %s", app.Key, err)
continue
Expand All @@ -261,6 +261,7 @@ func watchAppUpdates(ctx context.Context, watcher source.ConfigWatcher) {
if app, exists := apps[deleted]; exists {
log.Infof("Unloading app %s...", app.Key)
register.UnloadMaps(nil, getMapNames(app))
register.UnloadProviders(getProviderNames(app), app.Key)
delete(apps, app.Key)
} else {
log.Infof("Received an unload event for app %s, but couldn't find it.", deleted)
Expand All @@ -280,3 +281,17 @@ func getMapNames(app source.App) []string {

return names
}

func getProviderNames(app source.App) []string {
names := make([]string, 0, len(app.Providers))
for _, p := range app.Providers {
name, err := p.String("name", nil)
if err != nil {
log.Warnf("Encountered a provider in app %s with an empty name.", app.Key)
continue
}
names = append(names, name)
}

return names
}
2 changes: 1 addition & 1 deletion cmd/tegola_lambda/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func init() {
}

// register the providers
providers, err := register.Providers(provArr, nil)
providers, err := register.Providers(provArr, nil, "default")
if err != nil {
log.Fatal(err)
}
Expand Down
7 changes: 6 additions & 1 deletion provider/debug/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const (
)

func init() {
provider.Register(provider.TypeStd.Prefix()+Name, NewTileProvider, nil)
provider.Register(provider.TypeStd.Prefix()+Name, NewTileProvider)
}

// NewProvider Setups a debug provider. there are not currently any config params supported
Expand Down Expand Up @@ -113,3 +113,8 @@ func (p *Provider) Layers() ([]provider.LayerInfo, error) {

return ls, nil
}

// Cleanup is a no-op for the debug provider.
func (p *Provider) Cleanup() error {
return nil
}
5 changes: 5 additions & 0 deletions provider/gpkg/gpkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ func (p *Provider) Close() error {
return p.db.Close()
}

// Cleanup calls Close()
func (p *Provider) Cleanup() error {
return p.Close()
}

type GeomTableDetails struct {
geomFieldname string
geomType geom.Geometry
Expand Down
26 changes: 3 additions & 23 deletions provider/gpkg/gpkg_register.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
var colFinder *regexp.Regexp

func init() {
provider.Register(provider.TypeStd.Prefix()+Name, NewTileProvider, Cleanup)
provider.Register(provider.TypeStd.Prefix()+Name, NewTileProvider)
colFinder = regexp.MustCompile(`^(([a-zA-Z_][a-zA-Z0-9_]*)|"([^"]+)")\s`)
}

Expand All @@ -41,7 +41,8 @@ type featureTableDetails struct {
}

// Creates a config instance of the type NewTileProvider() requires including all available feature
// tables in the gpkg at 'gpkgPath'.
//
// tables in the gpkg at 'gpkgPath'.
func AutoConfig(gpkgPath string) (map[string]interface{}, error) {
// Get all feature tables
db, err := sql.Open("sqlite3", gpkgPath)
Expand Down Expand Up @@ -394,26 +395,5 @@ func NewTileProvider(config dict.Dicter, maps []provider.Map) (provider.Tiler, e
p.layers[layer.name] = layer
}

// track the provider so we can clean it up later
providers = append(providers, p)

return &p, err
}

// reference to all instantiated providers
var providers []Provider

// Cleanup will close all database connections and destroy all previously instantiated Provider instances
func Cleanup() {
if len(providers) > 0 {
log.Infof("cleaning up gpkg providers")
}

for i := range providers {
if err := providers[i].Close(); err != nil {
log.Errorf("err closing connection: %v", err)
}
}

providers = make([]Provider, 0)
}
46 changes: 0 additions & 46 deletions provider/gpkg/gpkg_register_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/go-spatial/geom"
"github.com/go-spatial/geom/cmp"
"github.com/go-spatial/tegola/dict"

_ "github.com/mattn/go-sqlite3"
)
Expand Down Expand Up @@ -1088,48 +1087,3 @@ func TestFeatureTableMetaData(t *testing.T) {
t.Run(tname, fn(tc))
}
}

func TestCleanup(t *testing.T) {
type tcase struct {
config dict.Dict
}

fn := func(tc tcase) func(*testing.T) {
return func(t *testing.T) {
_, err := NewTileProvider(tc.config, nil)
if err != nil {
t.Fatalf("err creating NewTileProvider: %v", err)
return
}

if len(providers) != 1 {
t.Errorf("expecting 1 providers, got %v", len(providers))
return
}

Cleanup()

if len(providers) != 0 {
t.Errorf("expecting 0 providers, got %v", len(providers))
return
}
}
}

tests := map[string]tcase{
"cleanup": {
config: map[string]interface{}{
"filepath": GPKGAthensFilePath,
"layers": []map[string]interface{}{
{"name": "a_points", "tablename": "amenities_points", "id_fieldname": "fid", "fields": []string{"amenity", "religion", "tourism", "shop"}},
{"name": "r_lines", "tablename": "rail_lines", "id_fieldname": "fid", "fields": []string{"railway", "bridge", "tunnel"}},
{"name": "rd_lines", "tablename": "roads_lines"},
},
},
},
}

for name, tc := range tests {
t.Run(name, fn(tc))
}
}
25 changes: 6 additions & 19 deletions provider/hana/hana.go
Original file line number Diff line number Diff line change
Expand Up @@ -597,9 +597,6 @@ func CreateProvider(config dict.Dicter, maps []provider.Map, providerType string
}
p.layers = lyrs

// track the provider so we can clean it up later
providers = append(providers, p)

return &p, nil
}

Expand Down Expand Up @@ -956,21 +953,11 @@ func (p Provider) MVTForLayers(ctx context.Context, tile provider.Tile, params p
return mvtBytes.Bytes(), nil
}

// Cleanup calls Close()
func (p *Provider) Cleanup() error {
p.Close()
return nil
}

// Close will close the Provider's database connectio
func (p *Provider) Close() { p.pool.Close() }

// reference to all instantiated providers
var providers []Provider

// Cleanup will close all database connections and destroy all previously instantiated Provider instances
func Cleanup() {
if len(providers) > 0 {
log.Infof("cleaning up HANA providers")
}

for i := range providers {
providers[i].Close()
}

providers = make([]Provider, 0)
}
33 changes: 16 additions & 17 deletions provider/hana/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
)

func init() {
provider.Register(provider.TypeStd.Prefix()+Name, NewTileProvider, Cleanup)
provider.MVTRegister(provider.TypeMvt.Prefix()+Name, NewMVTTileProvider, Cleanup)
provider.Register(provider.TypeStd.Prefix()+Name, NewTileProvider)
provider.MVTRegister(provider.TypeMvt.Prefix()+Name, NewMVTTileProvider)
}

const (
Expand All @@ -20,23 +20,22 @@ const (
// trying to create a driver. This Provider supports the following fields
// in the provided map[string]interface{} map:
//
// uri (string): [Required] HANA connection string
// name (string): [Required] Provider name is referenced from map layers
// srid (int): [Optional] The default SRID for the provider. Defaults to WebMercator (3857) but also supports WGS84 (4326)
// type (string): [Required] The type of data provider. must be "hana" to use this data provider
// layers (map[string]struct{}) — This is map of layers keyed by the layer name. Supports the following properties
// uri (string): [Required] HANA connection string
// name (string): [Required] Provider name is referenced from map layers
// srid (int): [Optional] The default SRID for the provider. Defaults to WebMercator (3857) but also supports WGS84 (4326)
// type (string): [Required] The type of data provider. must be "hana" to use this data provider
// layers (map[string]struct{}) — This is map of layers keyed by the layer name. Supports the following properties
//
// name (string): [Required] the name of the layer. This is used to reference this layer from map layers.
// tablename (string): [*Required] the name of the database table to query against. Required if sql is not defined.
// geometry_fieldname (string): [Optional] the name of the filed which contains the geometry for the feature. defaults to geom
// id_fieldname (string): [Optional] the name of the feature id field. defaults to gid
// fields ([]string): [Optional] a list of fields to include alongside the feature. Can be used if sql is not defined.
// srid (int): [Optional] the SRID of the layer. Supports 3857 (WebMercator) or 4326 (WGS84).
// sql (string): [*Required] custom SQL to use use. Required if tablename is not defined. Supports the following tokens:
//
// !BBOX! - [Required] will be replaced with the bounding box of the tile before the query is sent to the database.
// !ZOOM! - [Optional] will be replaced with the "Z" (zoom) value of the requested tile.
// name (string): [Required] the name of the layer. This is used to reference this layer from map layers.
// tablename (string): [*Required] the name of the database table to query against. Required if sql is not defined.
// geometry_fieldname (string): [Optional] the name of the filed which contains the geometry for the feature. defaults to geom
// id_fieldname (string): [Optional] the name of the feature id field. defaults to gid
// fields ([]string): [Optional] a list of fields to include alongside the feature. Can be used if sql is not defined.
// srid (int): [Optional] the SRID of the layer. Supports 3857 (WebMercator) or 4326 (WGS84).
// sql (string): [*Required] custom SQL to use use. Required if tablename is not defined. Supports the following tokens:
//
// !BBOX! - [Required] will be replaced with the bounding box of the tile before the query is sent to the database.
// !ZOOM! - [Optional] will be replaced with the "Z" (zoom) value of the requested tile.
func NewTileProvider(config dict.Dicter, maps []provider.Map) (provider.Tiler, error) {
return CreateProvider(config, maps, ProviderType)
}
Expand Down
3 changes: 3 additions & 0 deletions provider/mvt_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ type MVTTiler interface {

// MVTForLayers will return a MVT byte array or an error for the given layer names.
MVTForLayers(ctx context.Context, tile Tile, params Params, layers []Layer) ([]byte, error)

// Cleanup will do anything needed before the Tiler is removed.
Cleanup() error
}

// MVTInitFunc initialize a provider given a config map. The init function should validate the config map, and report any errors. This is called by the For function.
Expand Down
25 changes: 6 additions & 19 deletions provider/postgis/postgis.go
Original file line number Diff line number Diff line change
Expand Up @@ -640,9 +640,6 @@ func CreateProvider(config dict.Dicter, maps []provider.Map, providerType string
}
p.layers = lyrs

// track the provider so we can clean it up later
providers = append(providers, p)

return &p, nil
}

Expand Down Expand Up @@ -1067,21 +1064,11 @@ func (p Provider) MVTForLayers(ctx context.Context, tile provider.Tile, params p
return data.Bytes, nil
}

// Cleanup calls Close()
func (p *Provider) Cleanup() error {
p.Close()
return nil
}

// Close will close the Provider's database connectio
func (p *Provider) Close() { p.pool.Close() }

// reference to all instantiated providers
var providers []Provider

// Cleanup will close all database connections and destroy all previously instantiated Provider instances
func Cleanup() {
if len(providers) > 0 {
log.Infof("cleaning up postgis providers")
}

for i := range providers {
providers[i].Close()
}

providers = make([]Provider, 0)
}
Loading

0 comments on commit c0ff399

Please sign in to comment.