Skip to content

Commit

Permalink
GEOS-8947 gwc cluster safe via events
Browse files Browse the repository at this point in the history
  • Loading branch information
NielsCharlier committed Sep 28, 2018
1 parent 1844579 commit 966a8af
Show file tree
Hide file tree
Showing 10 changed files with 298 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ public boolean renameTo(Resource dest) {
eventsDelete));
resourceNotificationDispatcher.changed(
new ResourceNotification(
path(),
dest.path(),
eventsRename.get(0).getKind(),
System.currentTimeMillis(),
eventsRename));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,20 @@ public void fileEvents() throws Exception {
assertEquals(1, listener.getNotify().events().size());
}

listener.reset();
Resource fileE = store.get("DirC/FileE");
TestResourceListener listener2 = new TestResourceListener();
fileE.addListener(listener2);

fileD.renameTo(fileE);

assertNotNull(listener.getNotify());
assertEquals(Kind.ENTRY_DELETE, listener.getNotify().getKind());
assertNotNull(listener2.getNotify());
assertEquals(Kind.ENTRY_CREATE, listener2.getNotify().getKind());

fileD.removeListener(listener);
fileE.removeListener(listener2);
}

@Test
Expand Down Expand Up @@ -430,7 +443,7 @@ public void directoryEvents() throws Exception {
assertTrue(timeStamp > before);
Event e = listener.getNotify().events().get(0);
assertEquals(Kind.ENTRY_MODIFY, e.getKind());
assertEquals("DirC/FileD", e.getPath());
assertEquals("FileD", e.getPath());

listener.reset();
store.get("DirC").removeListener(listener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@ public CatalogConfiguration(
.initialCapacity(10) //
.maximumSize(100) //
.build(new TileLayerLoader(tileLayerCatalog));

tileLayerCatalog.addListener(
new TileLayerCatalogListener() {

@Override
public void onEvent(String layerId, TileLayerCatalogListener.Type type) {
if (type == TileLayerCatalogListener.Type.MODIFY
|| type == TileLayerCatalogListener.Type.DELETE) {
layerCache.invalidate(layerId);
}
}
});
}

/** @see TileLayerConfiguration#getIdentifier() */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
Expand All @@ -27,6 +30,9 @@
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.Resource;
import org.geoserver.platform.resource.Resource.Type;
import org.geoserver.platform.resource.ResourceListener;
import org.geoserver.platform.resource.ResourceNotification;
import org.geoserver.platform.resource.ResourceNotification.Event;
import org.geoserver.platform.resource.Resources;
import org.geoserver.platform.resource.Resources.ExtensionFilter;
import org.geotools.util.logging.Logging;
Expand All @@ -53,6 +59,10 @@ public class DefaultTileLayerCatalog implements TileLayerCatalog {

private volatile boolean initialized;

private Map<String, ResourceListener> listenersByFileName;

private List<TileLayerCatalogListener> listeners;

public DefaultTileLayerCatalog(
GeoServerResourceLoader resourceLoader, XMLConfiguration xmlPersisterFactory)
throws IOException {
Expand All @@ -70,13 +80,46 @@ public DefaultTileLayerCatalog(

this.layersByName = new ConcurrentHashMap<>();
this.layersById = new ConcurrentHashMap<>();
this.listenersByFileName = new ConcurrentHashMap<>();
this.listeners = new ArrayList<>();
this.initialized = false;

// setup xstream security for local classes
this.serializer = configuredXstream;
this.serializer.allowTypeHierarchy(GeoServerTileLayerInfo.class);
// have to use a string here because UnmodifiableSet is private
this.serializer.allowTypes(new String[] {"java.util.Collections$UnmodifiableSet"});
// automatically reload configuration on change
resourceLoader
.get(baseDirectory)
.addListener(
new ResourceListener() {
@Override
public void changed(ResourceNotification notify) {
for (Event event : notify.events()) {
if ((event.getKind() == ResourceNotification.Kind.ENTRY_CREATE
|| event.getKind()
== ResourceNotification.Kind
.ENTRY_MODIFY)
&& !event.getPath().contains("/")
&& event.getPath().toLowerCase().endsWith(".xml")
&& !listenersByFileName.containsKey(event.getPath())) {
GeoServerTileLayerInfoImpl info =
load(
resourceLoader
.get(baseDirectory)
.get(event.getPath()));
if (info != null) {
for (TileLayerCatalogListener listener : listeners) {
listener.onEvent(
info.getId(),
TileLayerCatalogListener.Type.CREATE);
}
}
}
}
}
});
}

@Override
Expand All @@ -88,7 +131,6 @@ public void reset() {

@Override
public void initialize() {

reset();

Resource baseDir = resourceLoader.get(baseDirectory);
Expand All @@ -102,24 +144,7 @@ public void initialize() {
.filter(r -> xmlFilter.accept(r))
.forEach(
res -> {
GeoServerTileLayerInfoImpl info;
try {
info = depersist(res);
} catch (Exception e) {
LOGGER.log(
Level.SEVERE,
"Error depersisting tile layer information from file "
+ res.name(),
e);
return;
}

layersByName.put(info.getName(), info.getId());
layersById.put(info.getId(), info);

if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.finer("Loaded tile layer '" + info.getName() + "'");
}
load(res);
});
this.initialized = true;
}
Expand Down Expand Up @@ -174,7 +199,9 @@ public GeoServerTileLayerInfo delete(final String tileLayerId) {
Resource file = getFile(tileLayerId);
layersById.remove(tileLayerId);
layersByName.remove(info.getName());
stopToListen(file);
file.delete();
listenersByFileName.remove(file.name());
}
return info;
} catch (IOException notFound) {
Expand Down Expand Up @@ -227,9 +254,72 @@ public GeoServerTileLayerInfo save(final GeoServerTileLayerInfo newValue) {
return oldValue;
}

private GeoServerTileLayerInfoImpl load(Resource res) {
GeoServerTileLayerInfoImpl info;
try {
info = depersist(res);
startToListen(res, info.getId());
} catch (Exception e) {
LOGGER.log(
Level.SEVERE,
"Error depersisting tile layer information from file " + res.name(),
e);
return null;
}

layersByName.put(info.getName(), info.getId());
layersById.put(info.getId(), info);

if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.finer("Loaded tile layer '" + info.getName() + "'");
}

return info;
}

private void reload(String id, Resource res) {
GeoServerTileLayerInfo old = layersById.remove(id);
if (old != null) {
layersByName.remove(old.getName());
}
load(res);
}

private void startToListen(Resource file, String tileLayerId) {
ResourceListener existingLayerListener =
new ResourceListener() {
@Override
public void changed(ResourceNotification notify) {
if (notify.getKind() == ResourceNotification.Kind.ENTRY_MODIFY) {
reload(tileLayerId, resourceLoader.get(notify.getPath()));
for (TileLayerCatalogListener listener : listeners) {
listener.onEvent(tileLayerId, TileLayerCatalogListener.Type.MODIFY);
}
} else if (notify.getKind() == ResourceNotification.Kind.ENTRY_DELETE) {
delete(tileLayerId);
for (TileLayerCatalogListener listener : listeners) {
listener.onEvent(tileLayerId, TileLayerCatalogListener.Type.DELETE);
}
}
}
};
listenersByFileName.put(file.name(), existingLayerListener);
file.addListener(existingLayerListener);
}

private void stopToListen(Resource file) {
ResourceListener existingLayerListener = listenersByFileName.get(file.name());
if (existingLayerListener != null) {
file.removeListener(existingLayerListener);
}
}

private void persist(GeoServerTileLayerInfo real) throws IOException {
final String tileLayerId = real.getId();
Resource file = getFile(tileLayerId);

stopToListen(file);

boolean cleanup = false;
if (file.getType() == Type.UNDEFINED) {
cleanup = true;
Expand Down Expand Up @@ -262,6 +352,8 @@ private void persist(GeoServerTileLayerInfo real) throws IOException {
throw propagate(e);
}
rename(tmp, file);

startToListen(file, tileLayerId);
}

private GeoServerTileLayerInfoImpl loadInternal(final String tileLayerId)
Expand Down Expand Up @@ -337,4 +429,9 @@ public String getLayerName(String layerId) {
public String getPersistenceLocation() {
return resourceLoader.get(baseDirectory).path();
}

@Override
public void addListener(TileLayerCatalogListener listener) {
listeners.add(listener);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

public interface TileLayerCatalog {

public void addListener(TileLayerCatalogListener listener);

public Set<String> getLayerIds();

public Set<String> getLayerNames();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* (c) 2018 Open Source Geospatial Foundation - all rights reserved
*
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.gwc.layer;

public interface TileLayerCatalogListener {

enum Type {
CREATE,
MODIFY,
DELETE
}

void onEvent(String layerId, Type type);
}

0 comments on commit 966a8af

Please sign in to comment.