8223490: Optimize search algorithm for determining default time zone
authorcoffeys
Tue, 17 Sep 2019 11:07:07 +0000
changeset 58186 8ee083465318
parent 58178 bb1aaed00341
child 58189 2f301425af62
8223490: Optimize search algorithm for determining default time zone Reviewed-by: naoto, rriggs
src/java.base/unix/native/libjava/TimeZone_md.c
--- a/src/java.base/unix/native/libjava/TimeZone_md.c	Tue Sep 17 09:51:02 2019 +0200
+++ b/src/java.base/unix/native/libjava/TimeZone_md.c	Tue Sep 17 11:07:07 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,8 @@
 #include "jvm.h"
 #include "TimeZone_md.h"
 
+static char *isFileIdentical(char* buf, size_t size, char *pathname);
+
 #define SKIP_SPACE(p)   while (*p == ' ' || *p == '\t') p++;
 
 #define RESTARTABLE(_cmd, _result) do { \
@@ -72,6 +74,8 @@
 static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime";
 #endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */
 
+static const char popularZones[][4] = {"UTC", "GMT"};
+
 #if defined(_AIX)
 static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
 #endif
@@ -121,11 +125,8 @@
 findZoneinfoFile(char *buf, size_t size, const char *dir)
 {
     DIR *dirp = NULL;
-    struct stat64 statbuf;
     struct dirent *dp = NULL;
     char *pathname = NULL;
-    int fd = -1;
-    char *dbuf = NULL;
     char *tz = NULL;
     int res;
 
@@ -134,6 +135,22 @@
         return NULL;
     }
 
+    if (strcmp(dir, ZONEINFO_DIR) == 0) {
+        /* fast path for 1st iteration */
+        for (unsigned int i = 0; i < sizeof (popularZones) / sizeof (popularZones[0]); i++) {
+            pathname = getPathName(dir, popularZones[i]);
+            if (pathname == NULL) {
+                continue;
+            }
+            tz = isFileIdentical(buf, size, pathname);
+            free((void *) pathname);
+            pathname = NULL;
+            if (tz != NULL) {
+                return tz;
+            }
+        }
+    }
+
     while ((dp = readdir(dirp)) != NULL) {
         /*
          * Skip '.' and '..' (and possibly other .* files)
@@ -162,58 +179,67 @@
         if (pathname == NULL) {
             break;
         }
-        RESTARTABLE(stat64(pathname, &statbuf), res);
-        if (res == -1) {
-            break;
-        }
 
-        if (S_ISDIR(statbuf.st_mode)) {
-            tz = findZoneinfoFile(buf, size, pathname);
-            if (tz != NULL) {
-                break;
-            }
-        } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
-            dbuf = (char *) malloc(size);
-            if (dbuf == NULL) {
-                break;
-            }
-            RESTARTABLE(open(pathname, O_RDONLY), fd);
-            if (fd == -1) {
-                break;
-            }
-            RESTARTABLE(read(fd, dbuf, size), res);
-            if (res != (ssize_t) size) {
-                break;
-            }
-            if (memcmp(buf, dbuf, size) == 0) {
-                tz = getZoneName(pathname);
-                if (tz != NULL) {
-                    tz = strdup(tz);
-                }
-                break;
-            }
-            free((void *) dbuf);
-            dbuf = NULL;
-            (void) close(fd);
-            fd = -1;
-        }
+        tz = isFileIdentical(buf, size, pathname);
         free((void *) pathname);
         pathname = NULL;
+        if (tz != NULL) {
+           break;
+        }
     }
 
     if (dirp != NULL) {
         (void) closedir(dirp);
     }
-    if (pathname != NULL) {
-        free((void *) pathname);
+    return tz;
+}
+
+/*
+ * Checks if the file pointed to by pathname matches
+ * the data contents in buf.
+ * Returns a representation of the timezone file name
+ * if file match is found, otherwise NULL.
+ */
+static char *
+isFileIdentical(char *buf, size_t size, char *pathname)
+{
+    char *possibleMatch = NULL;
+    struct stat64 statbuf;
+    char *dbuf = NULL;
+    int fd = -1;
+    int res;
+
+    RESTARTABLE(stat64(pathname, &statbuf), res);
+    if (res == -1) {
+        return NULL;
     }
-    if (fd != -1) {
+
+    if (S_ISDIR(statbuf.st_mode)) {
+        possibleMatch  = findZoneinfoFile(buf, size, pathname);
+    } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
+        dbuf = (char *) malloc(size);
+        if (dbuf == NULL) {
+            return NULL;
+        }
+        RESTARTABLE(open(pathname, O_RDONLY), fd);
+        if (fd == -1) {
+            goto freedata;
+        }
+        RESTARTABLE(read(fd, dbuf, size), res);
+        if (res != (ssize_t) size) {
+            goto freedata;
+        }
+        if (memcmp(buf, dbuf, size) == 0) {
+            possibleMatch = getZoneName(pathname);
+            if (possibleMatch != NULL) {
+                possibleMatch = strdup(possibleMatch);
+            }
+        }
+        freedata:
+        free((void *) dbuf);
         (void) close(fd);
     }
-    if (dbuf != NULL) {
-        free((void *) dbuf);
-    }
-    return tz;
+    return possibleMatch;
 }
 
 #if defined(__linux__) || defined(MACOSX)