1
1
#include " compile_cache.h"
2
+ #include < string>
2
3
#include " debug_utils-inl.h"
3
4
#include " env-inl.h"
4
5
#include " node_file.h"
@@ -27,15 +28,19 @@ uint32_t GetHash(const char* data, size_t size) {
27
28
return crc32 (crc, reinterpret_cast <const Bytef*>(data), size);
28
29
}
29
30
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;
39
44
}
40
45
41
46
uint32_t GetCacheKey (std::string_view filename, CachedCodeType type) {
@@ -63,6 +68,10 @@ v8::ScriptCompiler::CachedData* CompileCacheEntry::CopyCache() const {
63
68
data, cache_size, v8::ScriptCompiler::CachedData::BufferOwned);
64
69
}
65
70
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
+
66
75
void CompileCacheHandler::ReadCacheFile (CompileCacheEntry* entry) {
67
76
Debug (" [compile cache] reading cache from %s for %s %s..." ,
68
77
entry->cache_filename ,
@@ -100,12 +109,20 @@ void CompileCacheHandler::ReadCacheFile(CompileCacheEntry* entry) {
100
109
return ;
101
110
}
102
111
103
- Debug (" [%d %d %d %d]..." ,
112
+ Debug (" [%d %d %d %d %d]..." ,
113
+ headers[kMagicNumberOffset ],
104
114
headers[kCodeSizeOffset ],
105
115
headers[kCacheSizeOffset ],
106
116
headers[kCodeHashOffset ],
107
117
headers[kCacheHashOffset ]);
108
118
119
+ if (headers[kMagicNumberOffset ] != kCacheMagicNumber ) {
120
+ Debug (" magic number mismatch: expected %d, actual %d\n " ,
121
+ kCacheMagicNumber ,
122
+ headers[kMagicNumberOffset ]);
123
+ return ;
124
+ }
125
+
109
126
// Check the code size and hash which are already computed.
110
127
if (headers[kCodeSizeOffset ] != entry->code_size ) {
111
128
Debug (" code size mismatch: expected %d, actual %d\n " ,
@@ -202,11 +219,14 @@ CompileCacheEntry* CompileCacheHandler::GetOrInsert(
202
219
compiler_cache_store_.emplace (key, std::make_unique<CompileCacheEntry>());
203
220
auto * result = emplaced.first ->second .get ();
204
221
222
+ std::u8string cache_filename_u8 =
223
+ (compile_cache_dir_ / Uint32ToHex (key)).u8string ();
205
224
result->code_hash = code_hash;
206
225
result->code_size = code_utf8.length ();
207
226
result->cache_key = key;
208
227
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" ;
210
230
result->source_filename = filename_utf8.ToString ();
211
231
result->cache = nullptr ;
212
232
result->type = type;
@@ -264,6 +284,7 @@ void CompileCacheHandler::MaybeSave(CompileCacheEntry* entry,
264
284
}
265
285
266
286
// Layout of a cache file:
287
+ // [uint32_t] magic number
267
288
// [uint32_t] code size
268
289
// [uint32_t] code hash
269
290
// [uint32_t] cache size
@@ -301,14 +322,16 @@ void CompileCacheHandler::Persist() {
301
322
302
323
// Generating headers.
303
324
std::vector<uint32_t > headers (kHeaderCount );
325
+ headers[kMagicNumberOffset ] = kCacheMagicNumber ;
304
326
headers[kCodeSizeOffset ] = entry->code_size ;
305
327
headers[kCacheSizeOffset ] = cache_size;
306
328
headers[kCodeHashOffset ] = entry->code_hash ;
307
329
headers[kCacheHashOffset ] = cache_hash;
308
330
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 ]..." ,
310
332
entry->source_filename ,
311
333
entry->cache_filename ,
334
+ headers[kMagicNumberOffset ],
312
335
headers[kCodeSizeOffset ],
313
336
headers[kCacheSizeOffset ],
314
337
headers[kCodeHashOffset ],
@@ -335,53 +358,63 @@ CompileCacheHandler::CompileCacheHandler(Environment* env)
335
358
336
359
// Directory structure:
337
360
// - 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;
351
373
Debug (" [compile cache] resolved path %s + %s -> %s\n " ,
352
374
dir,
353
- compiler_cache_key_string ,
354
- cache_dir );
375
+ cache_tag ,
376
+ cache_dir_with_tag_str );
355
377
356
378
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;
362
386
}
363
387
364
388
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;
370
396
}
371
397
372
398
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 );
374
401
if (is_debug_) {
375
402
Debug (" [compile cache] creating cache directory %s...%s\n " ,
376
- cache_dir ,
403
+ cache_dir_with_tag_str ,
377
404
err < 0 ? uv_strerror (err) : " success" );
378
405
}
379
406
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;
381
411
}
382
412
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;
385
418
}
386
419
387
420
} // namespace node
0 commit comments