Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java @ 5779:ebec12def170
Datacage: Add a pool of builders to make it multi threadable.
XML DOM is not thread safe. Therefore the old implementation only allowed one thread
to use the builder at a time. As the complexity of the configuration
has increased over time this has become a bottleneck of the whole application
because it took quiet some time to build a result. Furthermore the builder code path
is visited very frequent. So many concurrent requests were piled up
resulting in long waits for the users.
To mitigate this problem a round robin pool of builders is used now.
Each of the pooled builders has an independent copy of the XML template
and can be run in parallel.
The number of builders is determined by the system property
'flys.datacage.pool.size'. It defaults to 4.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Sun, 21 Apr 2013 12:48:09 +0200 |
parents | cf4cc385e7c6 |
children |
comparison
equal
deleted
inserted
replaced
5778:4a1bd43e7aa6 | 5779:ebec12def170 |
---|---|
34 import de.intevation.flys.backend.SessionHolder; | 34 import de.intevation.flys.backend.SessionHolder; |
35 | 35 |
36 import de.intevation.artifactdatabase.data.StateData; | 36 import de.intevation.artifactdatabase.data.StateData; |
37 | 37 |
38 import de.intevation.flys.artifacts.datacage.templating.Builder; | 38 import de.intevation.flys.artifacts.datacage.templating.Builder; |
39 import de.intevation.flys.artifacts.datacage.templating.BuilderPool; | |
39 | 40 |
40 | 41 |
41 /** | 42 /** |
42 * Also accessible as Singleton with getInstance(). | 43 * Also accessible as Singleton with getInstance(). |
43 */ | 44 */ |
60 public static final String DEFAULT_TEMPLATE_PATH = | 61 public static final String DEFAULT_TEMPLATE_PATH = |
61 "${artifacts.config.dir}/meta-data.xml"; | 62 "${artifacts.config.dir}/meta-data.xml"; |
62 | 63 |
63 private static Recommendations INSTANCE; | 64 private static Recommendations INSTANCE; |
64 | 65 |
65 public static class BuilderProvider | 66 public static class BuilderPoolProvider |
66 { | 67 { |
67 protected Builder builder; | 68 protected BuilderPool builderPool; |
68 | 69 |
69 public BuilderProvider() { | 70 public BuilderPoolProvider() { |
70 } | 71 } |
71 | 72 |
72 public BuilderProvider(Builder builder) { | 73 public BuilderPoolProvider(BuilderPool builderPool) { |
73 this.builder = builder; | 74 this.builderPool = builderPool; |
74 } | 75 } |
75 | 76 |
76 public Builder getBuilder() { | 77 public BuilderPool getBuilderPool() { |
77 return builder; | 78 return builderPool; |
78 } | 79 } |
79 } // class BuilderProvider | 80 } // class BuilderProvider |
80 | 81 |
81 public static class FileBuilderProvider | 82 public static class FileBuilderPoolProvider |
82 extends BuilderProvider | 83 extends BuilderPoolProvider |
83 { | 84 { |
84 protected File file; | 85 protected File file; |
85 protected long lastModified; | 86 protected long lastModified; |
86 | 87 |
87 public FileBuilderProvider() { | 88 public FileBuilderPoolProvider() { |
88 } | 89 } |
89 | 90 |
90 public FileBuilderProvider(File file) { | 91 public FileBuilderPoolProvider(File file) { |
91 this.file = file; | 92 this.file = file; |
92 lastModified = Long.MIN_VALUE; | 93 lastModified = Long.MIN_VALUE; |
93 } | 94 } |
94 | 95 |
95 @Override | 96 @Override |
96 public synchronized Builder getBuilder() { | 97 public synchronized BuilderPool getBuilderPool() { |
97 long modified = file.lastModified(); | 98 long modified = file.lastModified(); |
98 if (modified > lastModified) { | 99 if (modified > lastModified) { |
99 lastModified = modified; | 100 lastModified = modified; |
100 try { | 101 try { |
101 Document template = loadTemplate(file); | 102 Document template = loadTemplate(file); |
102 builder = new Builder(template); | 103 builderPool = new BuilderPool(template); |
103 } | 104 } |
104 catch (IOException ioe) { | 105 catch (IOException ioe) { |
105 log.error(ioe); | 106 log.error(ioe); |
106 } | 107 } |
107 } | 108 } |
108 return builder; | 109 return builderPool; |
109 } | 110 } |
110 | 111 |
111 public BuilderProvider toStaticProvider() { | 112 public BuilderPoolProvider toStaticProvider() { |
112 return new BuilderProvider(builder); | 113 return new BuilderPoolProvider(builderPool); |
113 } | 114 } |
114 } // class BuilderProvider | 115 } // class BuilderProvider |
115 | 116 |
116 protected BuilderProvider builderProvider; | 117 protected BuilderPoolProvider builderPoolProvider; |
117 | 118 |
118 public Recommendations() { | 119 public Recommendations() { |
119 } | 120 } |
120 | 121 |
121 public Recommendations(BuilderProvider builderProvider) { | 122 public Recommendations(BuilderPoolProvider builderPoolProvider) { |
122 this.builderProvider = builderProvider; | 123 this.builderPoolProvider = builderPoolProvider; |
123 } | 124 } |
124 | 125 |
125 public Builder getBuilder() { | 126 public BuilderPool getBuilderPool() { |
126 return builderProvider.getBuilder(); | 127 return builderPoolProvider.getBuilderPool(); |
127 } | 128 } |
128 | 129 |
129 protected static void artifactToParameters( | 130 protected static void artifactToParameters( |
130 FLYSArtifact artifact, | 131 FLYSArtifact artifact, |
131 Map<String, Object> parameters | 132 Map<String, Object> parameters |
140 } | 141 } |
141 String key = sd.getName().replace('.', '-').toUpperCase(); | 142 String key = sd.getName().replace('.', '-').toUpperCase(); |
142 parameters.put(key, value); | 143 parameters.put(key, value); |
143 } | 144 } |
144 } | 145 } |
145 | |
146 | 146 |
147 /** | 147 /** |
148 * Put Key/Values from \param src to \param dst, but uppercase | 148 * Put Key/Values from \param src to \param dst, but uppercase |
149 * both Keys and Values. | 149 * both Keys and Values. |
150 */ | 150 */ |
268 if (userConnection != null) { | 268 if (userConnection != null) { |
269 connections.add(new Builder.NamedConnection( | 269 connections.add(new Builder.NamedConnection( |
270 CONNECTION_USER, userConnection, false)); | 270 CONNECTION_USER, userConnection, false)); |
271 } | 271 } |
272 | 272 |
273 | 273 getBuilderPool().build(connections, result, parameters); |
274 getBuilder().build(connections, result, parameters); | |
275 } | 274 } |
276 finally { | 275 finally { |
277 if (userConnection != null) { | 276 if (userConnection != null) { |
278 userConnection.close(); | 277 userConnection.close(); |
279 } | 278 } |
288 return INSTANCE; | 287 return INSTANCE; |
289 } | 288 } |
290 | 289 |
291 | 290 |
292 protected static Document loadTemplate(File file) throws IOException { | 291 protected static Document loadTemplate(File file) throws IOException { |
293 InputStream in = null; | 292 InputStream in = new FileInputStream(file); |
294 | 293 |
295 try { | 294 try { |
296 in = new FileInputStream(file); | |
297 | |
298 Document template = XMLUtils.parseDocument(in); | 295 Document template = XMLUtils.parseDocument(in); |
299 | |
300 if (template == null) { | 296 if (template == null) { |
301 throw new IOException("cannot load template"); | 297 throw new IOException("cannot load template"); |
302 } | 298 } |
303 return template; | 299 return template; |
304 } | 300 } |
305 finally { | 301 finally { |
306 if (in != null) { | 302 in.close(); |
307 try { | |
308 in.close(); | |
309 } | |
310 catch (IOException ioe) { | |
311 log.error(ioe); | |
312 } | |
313 } | |
314 } | 303 } |
315 } | 304 } |
316 | 305 |
317 public static Recommendations createRecommendations(File file) { | 306 public static Recommendations createRecommendations(File file) { |
318 log.debug("Recommendations.createBuilder"); | 307 log.debug("Recommendations.createBuilder"); |
320 if (!file.isFile() || !file.canRead()) { | 309 if (!file.isFile() || !file.canRead()) { |
321 log.error("Cannot open template file '" + file + "'"); | 310 log.error("Cannot open template file '" + file + "'"); |
322 return null; | 311 return null; |
323 } | 312 } |
324 | 313 |
325 FileBuilderProvider fbp = new FileBuilderProvider(file); | 314 FileBuilderPoolProvider fbp = new FileBuilderPoolProvider(file); |
326 | 315 |
327 if (fbp.getBuilder() == null) { | 316 if (fbp.getBuilderPool() == null) { |
328 log.error("failed loading builder"); | 317 log.error("failed loading builder"); |
329 return null; | 318 return null; |
330 } | 319 } |
331 | 320 |
332 BuilderProvider bp = DEVELOPMENT_MODE | 321 BuilderPoolProvider bp = DEVELOPMENT_MODE |
333 ? fbp | 322 ? fbp |
334 : fbp.toStaticProvider(); | 323 : fbp.toStaticProvider(); |
335 | 324 |
336 return new Recommendations(bp); | 325 return new Recommendations(bp); |
337 } | 326 } |