xslcache.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "xslcache.hpp"
  14. class CXslIncludeSignature : public CInterface, implements IInterface
  15. {
  16. private:
  17. StringBuffer filePath;
  18. offset_t fileSize;
  19. time_t fileTime;
  20. public:
  21. IMPLEMENT_IINTERFACE;
  22. CXslIncludeSignature(const char* path)
  23. {
  24. if(!path || !*path)
  25. throw MakeStringException(-1, "CXslIncludeSignature : path can't be emtpy");
  26. filePath.append(path);
  27. Owned<IFile> f = createIFile(path);
  28. if(f)
  29. {
  30. CDateTime modtime;
  31. f->getTime(NULL, &modtime, NULL);
  32. fileTime = modtime.getSimple();
  33. fileSize = f->size();
  34. }
  35. else
  36. {
  37. fileSize = 0;
  38. fileTime = 0;
  39. }
  40. }
  41. bool operator==(CXslIncludeSignature& incl)
  42. {
  43. return (streq(filePath.str(), incl.filePath.str())) && (fileSize == incl.fileSize) && (fileTime == incl.fileTime);
  44. }
  45. const char* getPath()
  46. {
  47. return filePath.str();
  48. }
  49. };
  50. class CXslIncludeCompare : public CInterface, implements IInterface
  51. {
  52. private:
  53. IArrayOf<CXslIncludeSignature> m_signatures;
  54. public:
  55. IMPLEMENT_IINTERFACE;
  56. CXslIncludeCompare(StringArray& includepaths)
  57. {
  58. ForEachItemIn(x, includepaths)
  59. {
  60. const char* path = includepaths.item(x);
  61. if(path && *path)
  62. m_signatures.append(*(new CXslIncludeSignature(path)));
  63. }
  64. }
  65. virtual ~CXslIncludeCompare()
  66. {
  67. }
  68. bool hasChanged()
  69. {
  70. ForEachItemIn(x, m_signatures)
  71. {
  72. CXslIncludeSignature &compiled = m_signatures.item(x);
  73. CXslIncludeSignature current(compiled.getPath());
  74. if(!(compiled == current))
  75. return true;
  76. }
  77. return false;
  78. }
  79. };
  80. class CXslEntry : public CInterface, implements IInterface
  81. {
  82. public:
  83. Owned<IXslBuffer> m_buffer;
  84. offset_t m_size;
  85. time_t createTime;
  86. time_t fileModTime;
  87. Owned<CXslIncludeCompare> m_includecomp;
  88. StringAttr m_cacheId;
  89. public:
  90. IMPLEMENT_IINTERFACE;
  91. CXslEntry(IXslBuffer* buffer)
  92. {
  93. assertex(buffer);
  94. m_size = 0;
  95. fileModTime = 0;
  96. time(&createTime);
  97. m_buffer.set(buffer);
  98. m_cacheId.set(buffer->getCacheId());
  99. if(m_buffer->getType() == IO_TYPE_FILE)
  100. {
  101. Owned<IFile> f = createIFile(buffer->getFileName());
  102. if(f)
  103. {
  104. CDateTime modtime;
  105. f->getTime(NULL, &modtime, NULL);
  106. fileModTime = modtime.getSimple();
  107. m_size = f->size();
  108. }
  109. }
  110. else
  111. m_size = buffer->getLen();
  112. }
  113. IXslBuffer* getBuffer()
  114. {
  115. return m_buffer.get();
  116. }
  117. bool isExpired(int cacheTimeout)
  118. {
  119. if (cacheTimeout==-1)
  120. return false;
  121. time_t t;
  122. time(&t);
  123. if(t > createTime + cacheTimeout)
  124. return true;
  125. return false;
  126. }
  127. bool match(CXslEntry* entry)
  128. {
  129. if(!entry)
  130. return false;
  131. if(m_buffer->getType() != entry->m_buffer->getType())
  132. return false;
  133. if (!m_cacheId.length())
  134. return false;
  135. return (entry->m_cacheId.length()) && (streq(m_cacheId.str(), entry->m_cacheId.str()));
  136. }
  137. bool equal(CXslEntry* entry, bool matched)
  138. {
  139. if(!entry)
  140. return false;
  141. if(!matched && !match(entry))
  142. return false;
  143. if (fileModTime != entry->fileModTime || m_size != entry->m_size)
  144. return false;
  145. if(m_includecomp.get() && m_includecomp->hasChanged())
  146. return false;
  147. return true;
  148. }
  149. void compile()
  150. {
  151. if(m_buffer.get())
  152. {
  153. m_buffer->compile();
  154. if(m_buffer->getIncludes().length())
  155. m_includecomp.setown(new CXslIncludeCompare(m_buffer->getIncludes()));
  156. }
  157. }
  158. };
  159. #define XSLTCACHESIZE 256
  160. class CXslCache : public CInterface, implements IXslCache
  161. {
  162. private:
  163. MapStringToMyClass<CXslEntry> xslMap;
  164. Mutex m_mutex;
  165. int m_cachetimeout;
  166. public:
  167. IMPLEMENT_IINTERFACE;
  168. CXslCache()
  169. {
  170. m_cachetimeout = XSLT_DEFAULT_CACHETIMEOUT;
  171. }
  172. virtual ~CXslCache()
  173. {
  174. }
  175. IXslBuffer* getCompiledXsl(IXslBuffer* xslbuffer, bool replace)
  176. {
  177. if(!xslbuffer)
  178. return NULL;
  179. synchronized block(m_mutex);
  180. Owned<CXslEntry> newEntry = new CXslEntry(xslbuffer);
  181. const char *cacheId = newEntry->m_cacheId.get();
  182. if (cacheId && *cacheId)
  183. {
  184. CXslEntry* cacheEntry = xslMap.getValue(cacheId);
  185. if (cacheEntry)
  186. {
  187. if(!replace && !cacheEntry->isExpired(m_cachetimeout) && cacheEntry->equal(newEntry, false))
  188. return cacheEntry->getBuffer();
  189. else
  190. xslMap.remove(cacheId);
  191. }
  192. }
  193. newEntry->compile();
  194. if (cacheId && *cacheId)
  195. {
  196. if (xslMap.count()>=XSLTCACHESIZE)
  197. freeOneCacheEntry();
  198. xslMap.setValue(cacheId, newEntry.get());
  199. }
  200. return xslbuffer;
  201. }
  202. void freeOneCacheEntry()
  203. {
  204. IMapping *oldest = NULL;
  205. time_t oldTime = 0;
  206. HashIterator iter(xslMap);
  207. for (iter.first(); iter.isValid(); iter.next())
  208. {
  209. CXslEntry *entry = xslMap.mapToValue(&iter.query());
  210. if (entry->isExpired(m_cachetimeout))
  211. {
  212. xslMap.removeExact(& static_cast<MappingStringToIInterface &>(iter.query()));
  213. return;
  214. }
  215. if (!oldest || entry->createTime < oldTime)
  216. {
  217. oldest=&iter.query();
  218. oldTime=entry->createTime;
  219. }
  220. }
  221. if (oldest)
  222. xslMap.removeExact(static_cast<MappingStringToIInterface *>(oldest));
  223. }
  224. void setCacheTimeout(int timeout)
  225. {
  226. m_cachetimeout = timeout;
  227. }
  228. };
  229. IXslCache* getXslCache()
  230. {
  231. static Owned<CXslCache> xslcache;
  232. if(!xslcache)
  233. xslcache.setown(new CXslCache());
  234. return xslcache.get();
  235. }
  236. IXslCache* getXslCache2()
  237. {
  238. static Owned<CXslCache> xslcache2;
  239. if(!xslcache2)
  240. xslcache2.setown(new CXslCache());
  241. return xslcache2.get();
  242. }