PageRenderTime 231ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/worldguard-legacy/src/main/java/com/sk89q/worldguard/protection/managers/RegionContainerImpl.java

https://gitlab.com/igserfurtmcschulserver/CustomWorldGuard
Java | 273 lines | 160 code | 29 blank | 84 comment | 10 complexity | cd34d9474cc31c9216d9fab5915a42d1 MD5 | raw file
  1. /*
  2. * WorldGuard, a suite of tools for Minecraft
  3. * Copyright (C) sk89q <http://www.sk89q.com>
  4. * Copyright (C) WorldGuard team and contributors
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU Lesser General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  14. * for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.sk89q.worldguard.protection.managers;
  20. import com.google.common.base.Supplier;
  21. import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
  22. import com.sk89q.worldguard.protection.managers.index.ChunkHashTable;
  23. import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
  24. import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
  25. import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
  26. import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
  27. import com.sk89q.worldguard.protection.managers.storage.StorageException;
  28. import com.sk89q.worldguard.util.Normal;
  29. import javax.annotation.Nullable;
  30. import java.util.*;
  31. import java.util.concurrent.ConcurrentHashMap;
  32. import java.util.concurrent.ConcurrentMap;
  33. import java.util.logging.Level;
  34. import java.util.logging.Logger;
  35. import static com.google.common.base.Preconditions.checkNotNull;
  36. /**
  37. * Manages different {@link RegionManager}s for different worlds or dimensions.
  38. *
  39. * <p>This is an internal class. Do not use it.</p>
  40. */
  41. public class RegionContainerImpl {
  42. private static final Logger log = Logger.getLogger(RegionContainerImpl.class.getCanonicalName());
  43. private static final int LOAD_ATTEMPT_INTERVAL = 1000 * 30;
  44. private static final int SAVE_INTERVAL = 1000 * 30;
  45. private final ConcurrentMap<Normal, RegionManager> mapping = new ConcurrentHashMap<Normal, RegionManager>();
  46. private final Object lock = new Object();
  47. private final RegionDriver driver;
  48. private final Supplier<? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
  49. private final Timer timer = new Timer();
  50. private final FlagRegistry flagRegistry;
  51. private final Set<Normal> failingLoads = new HashSet<Normal>();
  52. private final Set<RegionManager> failingSaves = Collections.synchronizedSet(
  53. Collections.newSetFromMap(new WeakHashMap<RegionManager, Boolean>()));
  54. /**
  55. * Create a new instance.
  56. *
  57. * @param driver the region store driver
  58. * @param flagRegistry the flag registry
  59. */
  60. public RegionContainerImpl(RegionDriver driver, FlagRegistry flagRegistry) {
  61. checkNotNull(driver);
  62. checkNotNull(flagRegistry, "flagRegistry");
  63. this.driver = driver;
  64. timer.schedule(new BackgroundLoader(), LOAD_ATTEMPT_INTERVAL, LOAD_ATTEMPT_INTERVAL);
  65. timer.schedule(new BackgroundSaver(), SAVE_INTERVAL, SAVE_INTERVAL);
  66. this.flagRegistry = flagRegistry;
  67. }
  68. /**
  69. * Get the region store driver.
  70. *
  71. * @return the driver
  72. */
  73. public RegionDriver getDriver() {
  74. return driver;
  75. }
  76. /**
  77. * Load the {@code RegionManager} for the world with the given name,
  78. * creating a new instance for the world if one does not exist yet.
  79. *
  80. * @param name the name of the world
  81. * @return a region manager, or {@code null} if loading failed
  82. */
  83. @Nullable
  84. public RegionManager load(String name) {
  85. checkNotNull(name);
  86. Normal normal = Normal.normal(name);
  87. synchronized (lock) {
  88. RegionManager manager = mapping.get(normal);
  89. if (manager != null) {
  90. return manager;
  91. } else {
  92. try {
  93. manager = createAndLoad(name);
  94. mapping.put(normal, manager);
  95. failingLoads.remove(normal);
  96. return manager;
  97. } catch (StorageException e) {
  98. log.log(Level.WARNING, "Failed to load the region data for '" + name + "' (periodic attempts will be made to load the data until success)", e);
  99. failingLoads.add(normal);
  100. return null;
  101. }
  102. }
  103. }
  104. }
  105. /**
  106. * Create a new region manager and load the data.
  107. *
  108. * @param name the name of the world
  109. * @return a region manager
  110. * @throws StorageException thrown if loading fals
  111. */
  112. private RegionManager createAndLoad(String name) throws StorageException {
  113. RegionDatabase store = driver.get(name);
  114. RegionManager manager = new RegionManager(store, indexFactory, flagRegistry);
  115. manager.load(); // Try loading, although it may fail
  116. return manager;
  117. }
  118. /**
  119. * Unload the region manager associated with the given world name.
  120. *
  121. * <p>If no region manager has been loaded for the given name, then
  122. * nothing will happen.</p>
  123. *
  124. * @param name the name of the world
  125. */
  126. public void unload(String name) {
  127. checkNotNull(name);
  128. Normal normal = Normal.normal(name);
  129. synchronized (lock) {
  130. RegionManager manager = mapping.get(normal);
  131. if (manager != null) {
  132. try {
  133. manager.save();
  134. } catch (StorageException e) {
  135. log.log(Level.WARNING, "Failed to save the region data for '" + name + "'", e);
  136. }
  137. mapping.remove(normal);
  138. failingSaves.remove(manager);
  139. }
  140. failingLoads.remove(normal);
  141. }
  142. }
  143. /**
  144. * Unload all region managers and save their contents before returning.
  145. * This message may block for an extended period of time.
  146. */
  147. public void unloadAll() {
  148. synchronized (lock) {
  149. for (Map.Entry<Normal, RegionManager> entry : mapping.entrySet()) {
  150. String name = entry.getKey().toString();
  151. RegionManager manager = entry.getValue();
  152. try {
  153. manager.saveChanges();
  154. } catch (StorageException e) {
  155. log.log(Level.WARNING, "Failed to save the region data for '" + name + "' while unloading the data for all worlds", e);
  156. }
  157. }
  158. mapping.clear();
  159. failingLoads.clear();
  160. failingSaves.clear();
  161. }
  162. }
  163. /**
  164. * Get the region manager for the given world name.
  165. *
  166. * @param name the name of the world
  167. * @return a region manager, or {@code null} if one was never loaded
  168. */
  169. @Nullable
  170. public RegionManager get(String name) {
  171. checkNotNull(name);
  172. return mapping.get(Normal.normal(name));
  173. }
  174. /**
  175. * Get an immutable list of loaded region managers.
  176. *
  177. * @return an immutable list
  178. */
  179. public List<RegionManager> getLoaded() {
  180. return Collections.unmodifiableList(new ArrayList<RegionManager>(mapping.values()));
  181. }
  182. /**
  183. * Get the a set of region managers that are failing to save.
  184. *
  185. * @return a set of region managers
  186. */
  187. public Set<RegionManager> getSaveFailures() {
  188. return new HashSet<RegionManager>(failingSaves);
  189. }
  190. /**
  191. * A task to save managers in the background.
  192. */
  193. private class BackgroundSaver extends TimerTask {
  194. @Override
  195. public void run() {
  196. synchronized (lock) {
  197. // Block loading of new region managers
  198. for (Map.Entry<Normal, RegionManager> entry : mapping.entrySet()) {
  199. String name = entry.getKey().toString();
  200. RegionManager manager = entry.getValue();
  201. try {
  202. if (manager.saveChanges()) {
  203. log.info("Region data changes made in '" + name + "' have been background saved");
  204. }
  205. failingSaves.remove(manager);
  206. } catch (StorageException e) {
  207. failingSaves.add(manager);
  208. log.log(Level.WARNING, "Failed to save the region data for '" + name + "' during a periodical save", e);
  209. } catch (Exception e) {
  210. failingSaves.add(manager);
  211. log.log(Level.WARNING, "An expected error occurred during a periodical save", e);
  212. }
  213. }
  214. }
  215. }
  216. }
  217. /**
  218. * A task to re-try loading region data that has not yet been
  219. * successfully loaded.
  220. */
  221. private class BackgroundLoader extends TimerTask {
  222. @Override
  223. public void run() {
  224. synchronized (lock) {
  225. if (!failingLoads.isEmpty()) {
  226. log.info("Attempting to load region data that has previously failed to load...");
  227. Iterator<Normal> it = failingLoads.iterator();
  228. while (it.hasNext()) {
  229. Normal normal = it.next();
  230. try {
  231. RegionManager manager = createAndLoad(normal.toString());
  232. mapping.put(normal, manager);
  233. it.remove();
  234. log.info("Successfully loaded region data for '" + normal.toString() + "'");
  235. } catch (StorageException e) {
  236. log.log(Level.WARNING, "Region data is still failing to load, at least for the world named '" + normal.toString() + "'", e);
  237. break;
  238. }
  239. }
  240. }
  241. }
  242. }
  243. }
  244. }