This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 98afc10300 [core] Rewrite oss tryToWriteAtomic using atomic putObject 
API (#8226) (#8228)
98afc10300 is described below

commit 98afc1030036e716ea13ca594cd2efd68646ec77
Author: MaxLinyun <[email protected]>
AuthorDate: Sat Jun 20 13:10:43 2026 +0800

    [core] Rewrite oss tryToWriteAtomic using atomic putObject API (#8226) 
(#8228)
---
 .../java/org/apache/paimon/fs/PluginFileIO.java    |  5 +++
 .../main/java/org/apache/paimon/oss/OSSFileIO.java | 39 ++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/paimon-common/src/main/java/org/apache/paimon/fs/PluginFileIO.java 
b/paimon-common/src/main/java/org/apache/paimon/fs/PluginFileIO.java
index 2af4919f08..d5b62a2944 100644
--- a/paimon-common/src/main/java/org/apache/paimon/fs/PluginFileIO.java
+++ b/paimon-common/src/main/java/org/apache/paimon/fs/PluginFileIO.java
@@ -91,6 +91,11 @@ public abstract class PluginFileIO implements FileIO, 
HadoopOptionsProvider {
         return wrap(() -> fileIO(src).rename(src, dst));
     }
 
+    @Override
+    public boolean tryToWriteAtomic(Path path, String content) throws 
IOException {
+        return wrap(() -> fileIO(path).tryToWriteAtomic(path, content));
+    }
+
     private FileIO fileIO(Path path) throws IOException {
         if (lazyFileIO == null) {
             synchronized (this) {
diff --git 
a/paimon-filesystems/paimon-oss-impl/src/main/java/org/apache/paimon/oss/OSSFileIO.java
 
b/paimon-filesystems/paimon-oss-impl/src/main/java/org/apache/paimon/oss/OSSFileIO.java
index 85d7e8cf9e..b9c18bf994 100644
--- 
a/paimon-filesystems/paimon-oss-impl/src/main/java/org/apache/paimon/oss/OSSFileIO.java
+++ 
b/paimon-filesystems/paimon-oss-impl/src/main/java/org/apache/paimon/oss/OSSFileIO.java
@@ -26,9 +26,12 @@ import org.apache.paimon.fs.TwoPhaseOutputStream;
 import org.apache.paimon.options.Options;
 import org.apache.paimon.utils.IOUtils;
 import org.apache.paimon.utils.ReflectionUtils;
+import org.apache.paimon.utils.StringUtils;
 
 import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.OSSException;
 import com.aliyun.oss.common.comm.ServiceClient;
+import com.aliyun.oss.model.ObjectMetadata;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.aliyun.oss.AliyunOSSFileSystem;
@@ -36,9 +39,11 @@ import 
org.apache.hadoop.fs.aliyun.oss.AliyunOSSFileSystemStore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.net.URI;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
@@ -180,6 +185,40 @@ public class OSSFileIO extends HadoopCompliantFileIO 
implements HadoopOptionsPro
         }
     }
 
+    @Override
+    public boolean tryToWriteAtomic(Path path, String content) throws 
IOException {
+        URI uri = path.toUri();
+        String bucket = uri.getHost();
+        String objectKey = uri.getPath().substring(1);
+        byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
+
+        ObjectMetadata metadata = new ObjectMetadata();
+        metadata.setContentLength(bytes.length);
+        metadata.setHeader("x-oss-forbid-overwrite", "true");
+
+        String sseAlgorithm =
+                
hadoopOptions.getString("fs.oss.server-side-encryption-algorithm", "");
+        if (StringUtils.isNotEmpty(sseAlgorithm)) {
+            metadata.setServerSideEncryption(sseAlgorithm);
+        }
+
+        AliyunOSSFileSystem fs = (AliyunOSSFileSystem) 
getFileSystem(path(path));
+        AliyunOSSFileSystemStore store = fs.getStore();
+        try {
+            OSSClient ossClient = ReflectionUtils.getPrivateFieldValue(store, 
"ossClient");
+            ossClient.putObject(bucket, objectKey, new 
ByteArrayInputStream(bytes), metadata);
+            return true;
+        } catch (OSSException e) {
+            if ("FileAlreadyExists".equals(e.getErrorCode())) {
+                LOG.warn("Failed to atomic write {}: object already exists", 
path);
+                return false;
+            }
+            throw new IOException("Failed to atomic write " + path, e);
+        } catch (Exception e) {
+            throw new IOException("Failed to atomic write " + path, e);
+        }
+    }
+
     @Override
     public void close() {
         if (!allowCache) {

Reply via email to