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

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 32add8eb2 perf(fileuri): skip URL parsing for plain local paths (#2278)
32add8eb2 is described below

commit 32add8eb24fb84a0263d00c870da441f482c049f
Author: Minh Vu <[email protected]>
AuthorDate: Fri Oct 23 19:00:18 2026 +0200

    perf(fileuri): skip URL parsing for plain local paths (#2278)
    
    * perf(fileuri): bypass general URL parser for plain local paths
    
    Signed-off-by: Minh Vu <[email protected]>
    
    * style(fileuri): satisfy Go lint in fast-path tests
    
    * style(fileuri): satisfy Go lint in fast-path tests
    
    * style(fileuri): satisfy Go lint in fast-path tests
    
    ---------
    
    Signed-off-by: Minh Vu <[email protected]>
---
 internal/fileuri/file_uri.go                     | 28 ++++++++
 internal/fileuri/file_uri_fastpath_bench_test.go | 53 +++++++++++++++
 internal/fileuri/file_uri_fastpath_test.go       | 84 ++++++++++++++++++++++++
 3 files changed, 165 insertions(+)

diff --git a/internal/fileuri/file_uri.go b/internal/fileuri/file_uri.go
index c4f5bf93f..6e97891cb 100644
--- a/internal/fileuri/file_uri.go
+++ b/internal/fileuri/file_uri.go
@@ -35,6 +35,15 @@ type FileURI struct {
 // Parse parses hierarchical and opaque file URIs using the same lexical rules
 // for every FileIO consumer.
 func Parse(name string) (FileURI, error) {
+       // Common hierarchical local file URIs have no URL components to decode.
+       // Escapes, delimiters, authorities and unusual characters use net/url.
+       if strings.HasPrefix(name, "file:///") {
+               path := name[len("file://"):]
+               if isPlainFilePath(path) {
+                       return FileURI{parsed: url.URL{Scheme: "file", Path: 
path}, path: path}, nil
+               }
+       }
+
        parsed, err := url.Parse(name)
        if err != nil {
                return FileURI{}, err
@@ -54,6 +63,25 @@ func Parse(name string) (FileURI, error) {
        return FileURI{parsed: *parsed, path: localPath}, nil
 }
 
+// isPlainFilePath accepts a conservative path alphabet that net/url leaves
+// untouched. Keeping special characters on the fallback preserves errors,
+// escaping, query strings, fragments and opaque URL semantics.
+func isPlainFilePath(path string) bool {
+       for i := range len(path) {
+               c := path[i]
+               if (c >= 'a' && c <= 'z') ||
+                       (c >= 'A' && c <= 'Z') ||
+                       (c >= '0' && c <= '9') ||
+                       c == '/' || c == '-' || c == '_' || c == '.' || c == 
'~' {
+                       continue
+               }
+
+               return false
+       }
+
+       return true
+}
+
 // Host returns the URI authority without changing its spelling.
 func (f FileURI) Host() string {
        return f.parsed.Host
diff --git a/internal/fileuri/file_uri_fastpath_bench_test.go 
b/internal/fileuri/file_uri_fastpath_bench_test.go
new file mode 100644
index 000000000..b976a15e7
--- /dev/null
+++ b/internal/fileuri/file_uri_fastpath_bench_test.go
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package fileuri
+
+import (
+       "strings"
+       "testing"
+)
+
+var parsedFileURISink FileURI
+
+// BenchmarkParseFileURI covers simple local paths and the fallback forms used
+// by FileIO. Compare the baseline and candidate commits with the same command.
+func BenchmarkParseFileURI(b *testing.B) {
+       for _, tc := range []struct {
+               name string
+               uri  string
+       }{
+               {"short-local", "file:///tmp/data.parquet"},
+               {"warehouse-path", 
"file:///srv/warehouse/database/table/data/2026/10/part-00000001.parquet"},
+               {"long-local", "file:///srv/" + 
strings.Repeat("partition_2026/", 20) + "data.parquet"},
+               {"escaped-local", "file:///srv/warehouse/data/a%20b.parquet"},
+               {"authority", "file://localhost/a/b.parquet"},
+               {"windows-drive", "file:///C:/Warehouse/data.parquet"},
+               {"opaque", "file:C:/Warehouse/data.parquet"},
+       } {
+               b.Run(tc.name, func(b *testing.B) {
+                       b.ReportAllocs()
+                       for range b.N {
+                               parsed, err := Parse(tc.uri)
+                               if err != nil {
+                                       b.Fatal(err)
+                               }
+                               parsedFileURISink = parsed
+                       }
+               })
+       }
+}
diff --git a/internal/fileuri/file_uri_fastpath_test.go 
b/internal/fileuri/file_uri_fastpath_test.go
new file mode 100644
index 000000000..72244e787
--- /dev/null
+++ b/internal/fileuri/file_uri_fastpath_test.go
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package fileuri
+
+import (
+       "net/url"
+       "reflect"
+       "strings"
+       "testing"
+)
+
+// Compare all URL fields, not just the decoded path. JoinPath depends on the
+// original hierarchical/opaque URL representation.
+func TestParseFileURIEquivalentToURLParser(t *testing.T) {
+       for _, uri := range []string{
+               "file:///", "file:////", "file:///tmp/data.parquet",
+               "file:///srv/data/a-b_1.2~3", "file:///srv//data/../file",
+               "file:///" + strings.Repeat("abc_0123456789/", 20),
+               "file:///C:/Warehouse/data.parquet", "file:///a%20b",
+               "file:///data?version=1", "file:///data#fragment",
+               "file:///data with spaces", "file:///café", 
"file:///data\\next",
+               "file:///data\x00nul", "file://localhost/a.parquet",
+               "file:C:/Warehouse/data.parquet", "file:///a%ZZ",
+               "FILE:///tmp/data.parquet", "s3:///tmp/data.parquet",
+       } {
+               got, gotErr := Parse(uri)
+               want, wantErr := url.Parse(uri)
+               valid := wantErr == nil && strings.EqualFold(want.Scheme, 
"file")
+               if (gotErr == nil) != valid {
+                       t.Errorf("Parse(%q): got error %v; url.Parse error %v; 
valid=%v", uri, gotErr, wantErr, valid)
+
+                       continue
+               }
+               if !valid {
+                       continue
+               }
+               if !reflect.DeepEqual(got.parsed, *want) {
+                       t.Errorf("Parse(%q): URL=%#v, want %#v", uri, 
got.parsed, *want)
+               }
+
+               wantPath := want.Path
+               if want.Opaque != "" {
+                       var err error
+                       wantPath, err = url.PathUnescape(want.Opaque)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+               }
+               if got.LocalPath(false) != wantPath {
+                       t.Errorf("Parse(%q): path=%q, want %q", uri, got.path, 
wantPath)
+               }
+               if want.Opaque == "" && got.JoinPath("metadata", "v1.json") != 
want.JoinPath("metadata", "v1.json").String() {
+                       t.Errorf("Parse(%q): JoinPath differs from net/url", 
uri)
+               }
+       }
+}
+
+func TestPlainFilePathAlphabet(t *testing.T) {
+       const safe = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-_.~"
+       const unsafe = "%?#\\ :@!$\x00é"
+       if !isPlainFilePath(safe) {
+               t.Fatal("simple URI alphabet rejected")
+       }
+       for _, c := range unsafe {
+               if isPlainFilePath("/tmp/" + string(c)) {
+                       t.Errorf("unsupported character %q accepted", c)
+               }
+       }
+}

Reply via email to