Skip to content

Commit 7148c77

Browse files
authored
Merge pull request #4845 from volodya-lombrozo/4840-cache-transpilation
feat(#4840): found critical bug in caching mechanism for transpilation process
2 parents 5420da4 + ccc4054 commit 7148c77

File tree

2 files changed

+102
-5
lines changed

2 files changed

+102
-5
lines changed

eo-maven-plugin/src/main/java/org/eolang/maven/MjTranspile.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,26 +173,34 @@ private int transpiled(
173173
final Supplier<String> hsh = new TojoHash(tojo);
174174
final AtomicBoolean rewrite = new AtomicBoolean(false);
175175
final Function<XML, XML> transform = this.transpilation(source);
176+
final String version = this.plugin.getVersion();
177+
final Path tail = base.relativize(target);
178+
final Path cdir = this.cache.toPath().resolve(MjTranspile.CACHE);
176179
new FpDefault(
177180
src -> {
178181
rewrite.compareAndSet(false, true);
179182
final long start = System.currentTimeMillis();
180183
final String res = transform.apply(xmir).toString();
181184
Logger.debug(
182185
this,
183-
"Transpiled %[file]s (%s) to %[file]s (%s) in %[ms]s (cache miss)",
186+
"Transpiled %[file]s (%s) to %[file]s (%s) in %[ms]s (cache miss), version: %s, hash: %s, tail: %s, cache enabled: %b, cache dir: %[file]s",
184187
source,
185188
MjTranspile.info(source),
186189
target,
187190
MjTranspile.info(target),
188-
System.currentTimeMillis() - start
191+
System.currentTimeMillis() - start,
192+
version,
193+
hsh.get(),
194+
tail,
195+
this.cacheEnabled,
196+
cdir
189197
);
190198
return res;
191199
},
192-
this.cache.toPath().resolve(MjTranspile.CACHE),
193-
this.plugin.getVersion(),
200+
cdir,
201+
version,
194202
hsh,
195-
base.relativize(target),
203+
tail,
196204
this.cacheEnabled
197205
).apply(source, target);
198206
return this.javaGenerated(rewrite.get(), target, hsh.get());

eo-maven-plugin/src/test/java/org/eolang/maven/FpDefaultTest.java

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.yegor256.Mktmp;
88
import com.yegor256.MktmpResolver;
99
import java.io.IOException;
10+
import java.nio.charset.StandardCharsets;
1011
import java.nio.file.Files;
1112
import java.nio.file.Path;
1213
import java.nio.file.Paths;
@@ -15,6 +16,7 @@
1516
import org.hamcrest.MatcherAssert;
1617
import org.hamcrest.Matchers;
1718
import org.junit.jupiter.api.Assertions;
19+
import org.junit.jupiter.api.Disabled;
1820
import org.junit.jupiter.api.Test;
1921
import org.junit.jupiter.api.extension.ExtendWith;
2022

@@ -336,6 +338,93 @@ void cachesEvenItIsZeroVersion(@Mktmp final Path temp) throws Exception {
336338
);
337339
}
338340

341+
/**
342+
* This test was added to mitigate an issue with the transpilation cache.
343+
* You can read more about it here:
344+
* <a href="https://github.com/objectionary/eo/issues/4840">4840</a>
345+
* If cache is missing, then transpilation should be performed.
346+
* @param temp Temporary directory
347+
* @throws Exception If fails
348+
*/
349+
@Test
350+
void transpilesIfCacheMiss(@Mktmp final Path temp) throws Exception {
351+
final Path cdir = temp.resolve("cache-folder").resolve("transpiled-folder");
352+
Files.createDirectories(cdir);
353+
final String content = "Source content - no cache";
354+
final Path source = FpDefaultTest.existedFile(
355+
temp.resolve("target/eo/1-parse/org/eolang/examples/fibonacci.xmir"),
356+
"old"
357+
);
358+
final Path target = FpDefaultTest.notExistedTarget(
359+
temp.resolve("target/eo/5-transpile/org/eolang/examples/fibonacci.xmir")
360+
);
361+
new FpDefault(
362+
src -> content,
363+
cdir,
364+
"1.0-SNAPSHOT",
365+
() -> "94641989dbaebef167cf67906a265d925bbb4e5b",
366+
Paths.get("org/eolang/examples/fibonacci.xmir"),
367+
true
368+
).apply(source, target);
369+
MatcherAssert.assertThat(
370+
"We expect a cache miss to trigger transpilation",
371+
new TextOf(target).asString(),
372+
Matchers.equalTo(content)
373+
);
374+
}
375+
376+
/**
377+
* We should use the transpilation cache if it existed before transpilation.
378+
* Current implementation of {@link FpDefault} relies on file timestamps to decide
379+
* whether to use the cache or not.
380+
* If the cache file is older than the source file, then the cache is ignored, which is
381+
* a critical issue for the transpilation step, because the source files are often
382+
* modified (e.g. by the parser) right before transpilation, making the cache
383+
* always older than the source files.
384+
* @param temp Temporary directory
385+
* @throws Exception If fails
386+
* @todo #4840:90min Implement proper cache validation mechanism.
387+
* Currently, FpDefault relies on file timestamps to decide whether to use
388+
* the cache or not. This approach is not reliable in many cases.
389+
* For example, in the transpilation step, the source files are often
390+
* modified right before transpilation, making the cache always older
391+
* than the source files.
392+
*/
393+
@Test
394+
@Disabled
395+
void doesNotTranspileIfCacheHitWhenCacheExistedBefore(@Mktmp final Path temp) throws Exception {
396+
final Path cdir = temp.resolve("cache-dir").resolve("transpiled-cache");
397+
Files.createDirectories(cdir);
398+
final Path cachefile = cdir
399+
.resolve("1.0-SNAPSHOT")
400+
.resolve("94641989dbaebef167cf67906a265d925bbb4e5b")
401+
.resolve("org/eolang/examples/fibonacci.xmir");
402+
Files.createDirectories(cachefile.getParent());
403+
final String cached = "transpilation results from cache";
404+
Files.write(cachefile, cached.getBytes(StandardCharsets.UTF_8));
405+
FpDefaultTest.makeOlder(cdir, 1000);
406+
final Path source = FpDefaultTest.existedFile(
407+
temp.resolve("target/eo/1-parse/org/eolang/examples/fibonacci.xmir"),
408+
"Source content"
409+
);
410+
final Path target = temp.resolve(
411+
"target/eo/5-transpile/org/eolang/examples/fibonacci.xmir"
412+
);
413+
new FpDefault(
414+
src -> "transpiled content",
415+
cdir,
416+
"1.0-SNAPSHOT",
417+
() -> "94641989dbaebef167cf67906a265d925bbb4e5b",
418+
Paths.get("org/eolang/examples/fibonacci.xmir"),
419+
true
420+
).apply(source, target);
421+
MatcherAssert.assertThat(
422+
"We expect that cache is used",
423+
new TextOf(target).asString(),
424+
Matchers.equalTo(cached)
425+
);
426+
}
427+
339428
/**
340429
* Returns the cache content.
341430
*/

0 commit comments

Comments
 (0)