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,10 @@ v8::ScriptCompiler::CachedData* CompileCacheEntry::CopyCache() const {
6368 data, cache_size, v8::ScriptCompiler::CachedData::BufferOwned);
6469}
6570
71+ // Used for identifying and verifying a file is a compile cache file.
72+ // See comments in CompileCacheHandler::Persist().
73+ constexpr uint32_t kCacheMagicNumber = 0x8adfdbb2 ;
74+
6675void CompileCacheHandler::ReadCacheFile (CompileCacheEntry* entry) {
6776 Debug (" [compile cache] reading cache from %s for %s %s..." ,
6877 entry->cache_filename ,
@@ -100,12 +109,20 @@ void CompileCacheHandler::ReadCacheFile(CompileCacheEntry* entry) {
100109 return ;
101110 }
102111
103- Debug (" [%d %d %d %d]..." ,
112+ Debug (" [%d %d %d %d %d]..." ,
113+ headers[kMagicNumberOffset ],
104114 headers[kCodeSizeOffset ],
105115 headers[kCacheSizeOffset ],
106116 headers[kCodeHashOffset ],
107117 headers[kCacheHashOffset ]);
108118
119+ if (headers[kMagicNumberOffset ] != kCacheMagicNumber ) {
120+ Debug (" magic number mismatch: expected %d, actual %d\n " ,
121+ kCacheMagicNumber ,
122+ headers[kMagicNumberOffset ]);
123+ return ;
124+ }
125+
109126 // Check the code size and hash which are already computed.
110127 if (headers[kCodeSizeOffset ] != entry->code_size ) {
111128 Debug (" code size mismatch: expected %d, actual %d\n " ,
@@ -202,11 +219,14 @@ CompileCacheEntry* CompileCacheHandler::GetOrInsert(
202219 compiler_cache_store_.emplace (key, std::make_unique<CompileCacheEntry>());
203220 auto * result = emplaced.first ->second .get ();
204221
222+ std::u8string cache_filename_u8 =
223+ (compile_cache_dir_ / Uint32ToHex (key)).u8string ();
205224 result->code_hash = code_hash;
206225 result->code_size = code_utf8.length ();
207226 result->cache_key = key;
208227 result->cache_filename =
209- (compile_cache_dir_ / Uint32ToHex (result->cache_key )).string ();
228+ std::string (cache_filename_u8.begin (), cache_filename_u8.end ()) +
229+ " .cache" ;
210230 result->source_filename = filename_utf8.ToString ();
211231 result->cache = nullptr ;
212232 result->type = type;
@@ -264,6 +284,7 @@ void CompileCacheHandler::MaybeSave(CompileCacheEntry* entry,
264284}
265285
266286// Layout of a cache file:
287+ // [uint32_t] magic number
267288// [uint32_t] code size
268289// [uint32_t] code hash
269290// [uint32_t] cache size
@@ -301,14 +322,16 @@ void CompileCacheHandler::Persist() {
301322
302323 // Generating headers.
303324 std::vector<uint32_t > headers (kHeaderCount );
325+ headers[kMagicNumberOffset ] = kCacheMagicNumber ;
304326 headers[kCodeSizeOffset ] = entry->code_size ;
305327 headers[kCacheSizeOffset ] = cache_size;
306328 headers[kCodeHashOffset ] = entry->code_hash ;
307329 headers[kCacheHashOffset ] = cache_hash;
308330
309- Debug (" [compile cache] writing cache for %s in %s [%d %d %d %d]..." ,
331+ Debug (" [compile cache] writing cache for %s in %s [%d %d %d %d %d ]..." ,
310332 entry->source_filename ,
311333 entry->cache_filename ,
334+ headers[kMagicNumberOffset ],
312335 headers[kCodeSizeOffset ],
313336 headers[kCacheSizeOffset ],
314337 headers[kCodeHashOffset ],
@@ -335,53 +358,63 @@ CompileCacheHandler::CompileCacheHandler(Environment* env)
335358
336359// Directory structure:
337360// - 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-
361+ // - $NODE_VERION-$ARCH-$CACHE_DATA_VERSION_TAG-$UID
362+ // - $FILENAME_AND_MODULE_TYPE_HASH.cache: a hash of filename + module type
363+ CompileCacheEnableResult CompileCacheHandler::Enable (Environment* env,
364+ const std::string& dir) {
365+ std::string cache_tag = GetCacheVersionTag ();
366+ std::string absolute_cache_dir_base = PathResolve (env, {dir});
367+ std::filesystem::path cache_dir_with_tag =
368+ std::filesystem::path (absolute_cache_dir_base) / cache_tag;
369+ std::u8string cache_dir_with_tag_u8 = cache_dir_with_tag.u8string ();
370+ std::string cache_dir_with_tag_str (cache_dir_with_tag_u8.begin (),
371+ cache_dir_with_tag_u8.end ());
372+ CompileCacheEnableResult result;
351373 Debug (" [compile cache] resolved path %s + %s -> %s\n " ,
352374 dir,
353- compiler_cache_key_string ,
354- cache_dir );
375+ cache_tag ,
376+ cache_dir_with_tag_str );
355377
356378 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 ;
379+ env,
380+ permission::PermissionScope::kFileSystemWrite ,
381+ cache_dir_with_tag_str))) {
382+ result.message = " Skipping compile cache because write permission for " +
383+ cache_dir_with_tag_str + " is not granted" ;
384+ result.status = CompileCacheEnableStatus::kFailed ;
385+ return result;
362386 }
363387
364388 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 ;
389+ env,
390+ permission::PermissionScope::kFileSystemRead ,
391+ cache_dir_with_tag_str))) {
392+ result.message = " Skipping compile cache because read permission for " +
393+ cache_dir_with_tag_str + " is not granted" ;
394+ result.status = CompileCacheEnableStatus::kFailed ;
395+ return result;
370396 }
371397
372398 fs::FSReqWrapSync req_wrap;
373- int err = fs::MKDirpSync (nullptr , &(req_wrap.req ), cache_dir, 0777 , nullptr );
399+ int err = fs::MKDirpSync (
400+ nullptr , &(req_wrap.req ), cache_dir_with_tag_str, 0777 , nullptr );
374401 if (is_debug_) {
375402 Debug (" [compile cache] creating cache directory %s...%s\n " ,
376- cache_dir ,
403+ cache_dir_with_tag_str ,
377404 err < 0 ? uv_strerror (err) : " success" );
378405 }
379406 if (err != 0 && err != UV_EEXIST) {
380- return false ;
407+ result.message =
408+ " Cannot create cache directory: " + std::string (uv_strerror (err));
409+ result.status = CompileCacheEnableStatus::kFailed ;
410+ return result;
381411 }
382412
383- compile_cache_dir_ = std::filesystem::path (cache_dir);
384- return true ;
413+ compile_cache_dir_str_ = absolute_cache_dir_base;
414+ result.cache_directory = absolute_cache_dir_base;
415+ compile_cache_dir_ = cache_dir_with_tag;
416+ result.status = CompileCacheEnableStatus::kEnabled ;
417+ return result;
385418}
386419
387420} // namespace node
0 commit comments