11#include " compile_cache.h"
2+ #include < string>
23#include " debug_utils-inl.h"
34#include " env-inl.h"
45#include " node_file.h"
@@ -27,15 +28,19 @@ uint32_t GetHash(const char* data, size_t size) {
2728 return crc32 (crc, reinterpret_cast <const Bytef*>(data), size);
2829}
2930
30- uint32_t GetCacheVersionTag () {
31- std::string_view node_version (NODE_VERSION);
32- uint32_t v8_tag = v8::ScriptCompiler::CachedDataVersionTag ();
33- uLong crc = crc32 (0L , Z_NULL, 0 );
34- crc = crc32 (crc, reinterpret_cast <const Bytef*>(&v8_tag), sizeof (uint32_t ));
35- crc = crc32 (crc,
36- reinterpret_cast <const Bytef*>(node_version.data ()),
37- node_version.size ());
38- return crc;
31+ std::string GetCacheVersionTag () {
32+ // On platforms where uids are available, use different folders for
33+ // different users to avoid cache miss due to permission incompatibility.
34+ // On platforms where uids are not available, bare with the cache miss.
35+ // This should be fine on Windows, as there local directories tend to be
36+ // user-specific.
37+ std::string tag = std::string (NODE_VERSION) + ' -' + std::string (NODE_ARCH) +
38+ ' -' +
39+ Uint32ToHex (v8::ScriptCompiler::CachedDataVersionTag ());
40+ #ifdef NODE_IMPLEMENTS_POSIX_CREDENTIALS
41+ tag += ' -' + std::to_string (getuid ());
42+ #endif
43+ return tag;
3944}
4045
4146uint32_t GetCacheKey (std::string_view filename, CachedCodeType type) {
@@ -63,6 +68,8 @@ v8::ScriptCompiler::CachedData* CompileCacheEntry::CopyCache() const {
6368 data, cache_size, v8::ScriptCompiler::CachedData::BufferOwned);
6469}
6570
71+ constexpr uint32_t kCacheMagicNumber = 0x8adfdbb2 ;
72+
6673void CompileCacheHandler::ReadCacheFile (CompileCacheEntry* entry) {
6774 Debug (" [compile cache] reading cache from %s for %s %s..." ,
6875 entry->cache_filename ,
@@ -100,12 +107,20 @@ void CompileCacheHandler::ReadCacheFile(CompileCacheEntry* entry) {
100107 return ;
101108 }
102109
103- Debug (" [%d %d %d %d]..." ,
110+ Debug (" [%d %d %d %d %d]..." ,
111+ headers[kMagicNumberOffset ],
104112 headers[kCodeSizeOffset ],
105113 headers[kCacheSizeOffset ],
106114 headers[kCodeHashOffset ],
107115 headers[kCacheHashOffset ]);
108116
117+ if (headers[kMagicNumberOffset ] != kCacheMagicNumber ) {
118+ Debug (" magic number mismatch: expected %d, actual %d\n " ,
119+ kCacheMagicNumber ,
120+ headers[kMagicNumberOffset ]);
121+ return ;
122+ }
123+
109124 // Check the code size and hash which are already computed.
110125 if (headers[kCodeSizeOffset ] != entry->code_size ) {
111126 Debug (" code size mismatch: expected %d, actual %d\n " ,
@@ -202,11 +217,14 @@ CompileCacheEntry* CompileCacheHandler::GetOrInsert(
202217 compiler_cache_store_.emplace (key, std::make_unique<CompileCacheEntry>());
203218 auto * result = emplaced.first ->second .get ();
204219
220+ std::u8string cache_filename_u8 =
221+ (compile_cache_dir_ / Uint32ToHex (key)).u8string ();
205222 result->code_hash = code_hash;
206223 result->code_size = code_utf8.length ();
207224 result->cache_key = key;
208225 result->cache_filename =
209- (compile_cache_dir_ / Uint32ToHex (result->cache_key )).string ();
226+ std::string (cache_filename_u8.begin (), cache_filename_u8.end ()) +
227+ " .cache" ;
210228 result->source_filename = filename_utf8.ToString ();
211229 result->cache = nullptr ;
212230 result->type = type;
@@ -264,6 +282,7 @@ void CompileCacheHandler::MaybeSave(CompileCacheEntry* entry,
264282}
265283
266284// Layout of a cache file:
285+ // [uint32_t] magic number
267286// [uint32_t] code size
268287// [uint32_t] code hash
269288// [uint32_t] cache size
@@ -301,14 +320,16 @@ void CompileCacheHandler::Persist() {
301320
302321 // Generating headers.
303322 std::vector<uint32_t > headers (kHeaderCount );
323+ headers[kMagicNumberOffset ] = kCacheMagicNumber ;
304324 headers[kCodeSizeOffset ] = entry->code_size ;
305325 headers[kCacheSizeOffset ] = cache_size;
306326 headers[kCodeHashOffset ] = entry->code_hash ;
307327 headers[kCacheHashOffset ] = cache_hash;
308328
309- Debug (" [compile cache] writing cache for %s in %s [%d %d %d %d]..." ,
329+ Debug (" [compile cache] writing cache for %s in %s [%d %d %d %d %d ]..." ,
310330 entry->source_filename ,
311331 entry->cache_filename ,
332+ headers[kMagicNumberOffset ],
312333 headers[kCodeSizeOffset ],
313334 headers[kCacheSizeOffset ],
314335 headers[kCodeHashOffset ],
@@ -335,53 +356,63 @@ CompileCacheHandler::CompileCacheHandler(Environment* env)
335356
336357// Directory structure:
337358// - Compile cache directory (from NODE_COMPILE_CACHE)
338- // - <cache_version_tag_1>: hash of CachedDataVersionTag + NODE_VERESION
339- // - <cache_version_tag_2>
340- // - <cache_version_tag_3>
341- // - <cache_file_1>: a hash of filename + module type
342- // - <cache_file_2>
343- // - <cache_file_3>
344- bool CompileCacheHandler::InitializeDirectory (Environment* env,
345- const std::string& dir) {
346- compiler_cache_key_ = GetCacheVersionTag ();
347- std::string compiler_cache_key_string = Uint32ToHex (compiler_cache_key_);
348- std::vector<std::string_view> paths = {dir, compiler_cache_key_string};
349- std::string cache_dir = PathResolve (env, paths);
350-
359+ // - $NODE_VERION-$ARCH-$CACHE_DATA_VERSION_TAG-$UID
360+ // - $FILENAME_AND_MODULE_TYPE_HASH.cache: a hash of filename + module type
361+ CompileCacheEnableResult CompileCacheHandler::Enable (Environment* env,
362+ const std::string& dir) {
363+ std::string cache_tag = GetCacheVersionTag ();
364+ std::string absolute_cache_dir_base = PathResolve (env, {dir});
365+ std::filesystem::path cache_dir_with_tag =
366+ std::filesystem::path (absolute_cache_dir_base) / cache_tag;
367+ std::u8string cache_dir_with_tag_u8 = cache_dir_with_tag.u8string ();
368+ std::string cache_dir_with_tag_str (cache_dir_with_tag_u8.begin (),
369+ cache_dir_with_tag_u8.end ());
370+ CompileCacheEnableResult result;
351371 Debug (" [compile cache] resolved path %s + %s -> %s\n " ,
352372 dir,
353- compiler_cache_key_string ,
354- cache_dir );
373+ cache_tag ,
374+ cache_dir_with_tag_str );
355375
356376 if (UNLIKELY (!env->permission ()->is_granted (
357- env, permission::PermissionScope::kFileSystemWrite , cache_dir))) {
358- Debug (" [compile cache] skipping cache because write permission for %s "
359- " is not granted\n " ,
360- cache_dir);
361- return false ;
377+ env,
378+ permission::PermissionScope::kFileSystemWrite ,
379+ cache_dir_with_tag_str))) {
380+ result.message = " Skipping compile cache because write permission for " +
381+ cache_dir_with_tag_str + " is not granted" ;
382+ result.status = CompileCacheEnableStatus::kFailed ;
383+ return result;
362384 }
363385
364386 if (UNLIKELY (!env->permission ()->is_granted (
365- env, permission::PermissionScope::kFileSystemRead , cache_dir))) {
366- Debug (" [compile cache] skipping cache because read permission for %s "
367- " is not granted\n " ,
368- cache_dir);
369- return false ;
387+ env,
388+ permission::PermissionScope::kFileSystemRead ,
389+ cache_dir_with_tag_str))) {
390+ result.message = " Skipping compile cache because read permission for " +
391+ cache_dir_with_tag_str + " is not granted" ;
392+ result.status = CompileCacheEnableStatus::kFailed ;
393+ return result;
370394 }
371395
372396 fs::FSReqWrapSync req_wrap;
373- int err = fs::MKDirpSync (nullptr , &(req_wrap.req ), cache_dir, 0777 , nullptr );
397+ int err = fs::MKDirpSync (
398+ nullptr , &(req_wrap.req ), cache_dir_with_tag_str, 0777 , nullptr );
374399 if (is_debug_) {
375400 Debug (" [compile cache] creating cache directory %s...%s\n " ,
376- cache_dir ,
401+ cache_dir_with_tag_str ,
377402 err < 0 ? uv_strerror (err) : " success" );
378403 }
379404 if (err != 0 && err != UV_EEXIST) {
380- return false ;
405+ result.message =
406+ " Cannot create cache directory: " + std::string (uv_strerror (err));
407+ result.status = CompileCacheEnableStatus::kFailed ;
408+ return result;
381409 }
382410
383- compile_cache_dir_ = std::filesystem::path (cache_dir);
384- return true ;
411+ compile_cache_dir_str_ = absolute_cache_dir_base;
412+ result.cache_directory = absolute_cache_dir_base;
413+ compile_cache_dir_ = cache_dir_with_tag;
414+ result.status = CompileCacheEnableStatus::kEnabled ;
415+ return result;
385416}
386417
387418} // namespace node
0 commit comments