in dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java [220:336]
public void doSaveProperties(long version) {
if (version < lastCacheChanged.get()) {
return;
}
if (file == null) {
return;
}
// Save
File lockfile = null;
try {
lockfile = new File(file.getAbsolutePath() + ".lock");
if (!lockfile.exists()) {
lockfile.createNewFile();
}
try (RandomAccessFile raf = new RandomAccessFile(lockfile, "rw");
FileChannel channel = raf.getChannel()) {
FileLock lock = channel.tryLock();
if (lock == null) {
IOException ioException = new IOException(
"Can not lock the registry cache file " + file.getAbsolutePath() + ", "
+ "ignore and retry later, maybe multi java process use the file, please config: dubbo.registry.file=xxx.properties");
// 1-9 failed to read / save registry cache file.
logger.warn(
REGISTRY_FAILED_READ_WRITE_CACHE_FILE,
CAUSE_MULTI_DUBBO_USING_SAME_FILE,
"",
"Adjust dubbo.registry.file.",
ioException);
throw ioException;
}
// Save
try {
if (!file.exists()) {
file.createNewFile();
}
Properties tmpProperties;
if (syncSaveFile) {
// When syncReport = true, properties.setProperty and properties.store are called from the same
// thread(reportCacheExecutor), so deep copy is not required
tmpProperties = properties;
} else {
// Using properties.setProperty and properties.store method will cause lock contention
// under multi-threading, so deep copy a new container
tmpProperties = new Properties();
Set<Map.Entry<Object, Object>> entries = properties.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
tmpProperties.setProperty((String) entry.getKey(), (String) entry.getValue());
}
}
try (FileOutputStream outputFile = new FileOutputStream(file)) {
tmpProperties.store(outputFile, "Dubbo Registry Cache");
}
} finally {
lock.release();
}
}
} catch (Throwable e) {
savePropertiesRetryTimes.incrementAndGet();
if (savePropertiesRetryTimes.get() >= MAX_RETRY_TIMES_SAVE_PROPERTIES) {
if (e instanceof OverlappingFileLockException) {
// fix #9341, ignore OverlappingFileLockException
logger.info("Failed to save registry cache file for file overlapping lock exception, file name "
+ file.getName());
} else {
// 1-9 failed to read / save registry cache file.
logger.warn(
REGISTRY_FAILED_READ_WRITE_CACHE_FILE,
CAUSE_MULTI_DUBBO_USING_SAME_FILE,
"",
"Failed to save registry cache file after retrying " + MAX_RETRY_TIMES_SAVE_PROPERTIES
+ " times, cause: " + e.getMessage(),
e);
}
savePropertiesRetryTimes.set(0);
return;
}
if (version < lastCacheChanged.get()) {
savePropertiesRetryTimes.set(0);
return;
} else {
registryCacheExecutor.schedule(
() -> doSaveProperties(lastCacheChanged.incrementAndGet()),
DEFAULT_INTERVAL_SAVE_PROPERTIES,
TimeUnit.MILLISECONDS);
}
if (!(e instanceof OverlappingFileLockException)) {
logger.warn(
REGISTRY_FAILED_READ_WRITE_CACHE_FILE,
CAUSE_MULTI_DUBBO_USING_SAME_FILE,
"However, the retrying count limit is not exceeded. Dubbo will still try.",
"Failed to save registry cache file, will retry, cause: " + e.getMessage(),
e);
}
} finally {
if (lockfile != null) {
if (!lockfile.delete()) {
// 1-10 Failed to delete lock file.
logger.warn(
REGISTRY_FAILED_DELETE_LOCKFILE,
"",
"",
String.format("Failed to delete lock file [%s]", lockfile.getName()));
}
}
}
}