- 
                Notifications
    You must be signed in to change notification settings 
- Fork 442
Configurable Retry Logic I - Statement Retry #2396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
          
     Merged
      
      
    
  
     Merged
                    Changes from 56 commits
      Commits
    
    
            Show all changes
          
          
            62 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      50f3f18
              
                Trying on a new branch b/c I keep getting build failures and I have n…
              
              
                Jeffery-Wasty 74e007a
              
                Adding back retryExec
              
              
                Jeffery-Wasty 726fc85
              
                More
              
              
                Jeffery-Wasty b463d81
              
                Missing null check
              
              
                Jeffery-Wasty 1ffc13e
              
                Next to final
              
              
                Jeffery-Wasty d18b021
              
                Removed mssql-jdbc.properties
              
              
                Jeffery-Wasty 5ff2737
              
                Set up should start fresh + remove passwords to pass on pipeline
              
              
                Jeffery-Wasty 9b3863d
              
                Minor cleanup
              
              
                Jeffery-Wasty 16e0224
              
                Minor cleanup
              
              
                Jeffery-Wasty 632c168
              
                Another missing null check
              
              
                Jeffery-Wasty be55749
              
                Fix for timeout tests
              
              
                Jeffery-Wasty 68c683a
              
                Added timing tests + test comments
              
              
                Jeffery-Wasty 9730690
              
                Formatting
              
              
                Jeffery-Wasty d9d9b38
              
                Added a multiple rules test
              
              
                Jeffery-Wasty 07fd965
              
                Trying on a new branch b/c I keep getting build failures and I have n…
              
              
                Jeffery-Wasty 03aa1b7
              
                More changes
              
              
                Jeffery-Wasty 83fecee
              
                Undo LimitEscapeTest changes
              
              
                Jeffery-Wasty 1f3e891
              
                Remove redundant files
              
              
                Jeffery-Wasty e2b2bd0
              
                Final?
              
              
                Jeffery-Wasty 2cb9650
              
                Remove mssql-jdpc.properties file
              
              
                Jeffery-Wasty 4844288
              
                sync --> lock
              
              
                Jeffery-Wasty bb3b253
              
                Remove problematic test
              
              
                Jeffery-Wasty 00c3545
              
                Since error is unclear, try removing last test
              
              
                Jeffery-Wasty 1e79a1f
              
                Adding back connection test
              
              
                Jeffery-Wasty f8273ea
              
                I need debugging
              
              
                Jeffery-Wasty a74cffe
              
                Fix for MI
              
              
                Jeffery-Wasty 5d80ecd
              
                if condition for min time assertion
              
              
                Jeffery-Wasty 11e84cc
              
                Leftover debug code, cleanup
              
              
                Jeffery-Wasty 141fc0c
              
                Mistaken changes committed
              
              
                Jeffery-Wasty 9f24ce4
              
                More liberal time windows
              
              
                Jeffery-Wasty 04aff85
              
                Remove connection part
              
              
                Jeffery-Wasty 193620f
              
                Missed some parts where connection retry was still included.
              
              
                Jeffery-Wasty 5e5858f
              
                Forgot one more part
              
              
                Jeffery-Wasty fdb38d8
              
                Added (most) PR comment revisions.
              
              
                Jeffery-Wasty 6465a95
              
                Add comments for specified and public facing methods
              
              
                Jeffery-Wasty ff374b0
              
                Merge branch 'main' into CRL2
              
              
                Jeffery-Wasty 46951f1
              
                Added a missing test
              
              
                Jeffery-Wasty eb1d508
              
                Merge branch 'CRL2' of https://github.com/microsoft/mssql-jdbc into CRL2
              
              
                Jeffery-Wasty 0be2a3b
              
                More tests
              
              
                Jeffery-Wasty 5d45f4d
              
                Added more missing tests
              
              
                Jeffery-Wasty cb24aa8
              
                Resolve retryCount test failure
              
              
                Jeffery-Wasty 7634c39
              
                Remove eaten exceptions
              
              
                Jeffery-Wasty 57fac74
              
                Removed the file not found exception as we read for file in all cases…
              
              
                Jeffery-Wasty 151d40f
              
                Added a proper file read
              
              
                Jeffery-Wasty 7aebfb2
              
                Delete mssql-jdbc.properties
              
              
                Jeffery-Wasty 763144d
              
                Added more coverage and minor fixes, ready for review again
              
              
                Jeffery-Wasty cbdc239
              
                Merge branch 'CRL2' of https://github.com/microsoft/mssql-jdbc into CRL2
              
              
                Jeffery-Wasty 7e267b1
              
                Fixed read file test
              
              
                Jeffery-Wasty a50fdf9
              
                Addressed recent pr comments
              
              
                Jeffery-Wasty 728866d
              
                Merge branch 'main' into CRL2
              
              
                Jeffery-Wasty 04c25f9
              
                Remove double locking
              
              
                Jeffery-Wasty c4e6153
              
                Merge branch 'CRL2' of https://github.com/microsoft/mssql-jdbc into CRL2
              
              
                Jeffery-Wasty c0fa29a
              
                Remove unneeded variable
              
              
                Jeffery-Wasty cc1540c
              
                Revisions after PR review
              
              
                Jeffery-Wasty 9269c18
              
                PR review update
              
              
                Jeffery-Wasty bbcdf8d
              
                Rename R_AKVURLInvalid as its use is no longer AKV specific
              
              
                Jeffery-Wasty 091ed78
              
                Add back logging
              
              
                Jeffery-Wasty 9aa47ca
              
                Typo
              
              
                Jeffery-Wasty 49b7b44
              
                Removed unneeded comment
              
              
                Jeffery-Wasty 34cfa4b
              
                Make static variables thread-safe
              
              
                Jeffery-Wasty df67a98
              
                Timing
              
              
                Jeffery-Wasty 7c7fc92
              
                JavaDoc cleanup.
              
              
                Jeffery-Wasty File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
        
          
          
            206 changes: 206 additions & 0 deletions
          
          206 
        
  src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,206 @@ | ||
| /* | ||
| * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made | ||
| * available under the terms of the MIT License. See the LICENSE file in the project root for more information. | ||
| */ | ||
|  | ||
| package com.microsoft.sqlserver.jdbc; | ||
|  | ||
| import java.io.BufferedReader; | ||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.io.FileReader; | ||
| import java.io.IOException; | ||
| import java.net.URI; | ||
| import java.net.URISyntaxException; | ||
| import java.text.MessageFormat; | ||
| import java.util.Collections; | ||
| import java.util.Date; | ||
| import java.util.HashMap; | ||
| import java.util.LinkedList; | ||
| import java.util.Map; | ||
|  | ||
|  | ||
| /** | ||
| * Allows configurable statement retry through the use of the 'retryExec' connection property. Each rule read in is | ||
| * converted to ConfigRetryRule objects, which are stored and referenced during statement retry. | ||
| * | ||
| */ | ||
| public class ConfigurableRetryLogic { | ||
|         
                  Jeffery-Wasty marked this conversation as resolved.
              Show resolved
            Hide resolved         
                  Jeffery-Wasty marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| private final static int INTERVAL_BETWEEN_READS_IN_MS = 30000; | ||
| private final static String DEFAULT_PROPS_FILE = "mssql-jdbc.properties"; | ||
| private static final java.util.logging.Logger CONFIGURABLE_RETRY_LOGGER = java.util.logging.Logger | ||
| .getLogger("com.microsoft.sqlserver.jdbc.ConfigurableRetryLogic"); | ||
| private static ConfigurableRetryLogic singleInstance = null; | ||
|         
                  Jeffery-Wasty marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| private static long timeLastModified; | ||
|         
                  Jeffery-Wasty marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| private static long timeLastRead; | ||
| private static String lastQuery = ""; // The last query executed (used when rule is process-dependent) | ||
| private static String prevRulesFromConnectionString = ""; | ||
| private static HashMap<Integer, ConfigurableRetryRule> stmtRules = new HashMap<>(); | ||
| private static final String SEMI_COLON = ";"; | ||
| private static final String COMMA = ","; | ||
| private static final String FORWARD_SLASH = "/"; | ||
| private static final String EQUALS_SIGN = "="; | ||
| private static final String RETRY_EXEC = "retryExec"; | ||
|  | ||
| private ConfigurableRetryLogic() throws SQLServerException { | ||
| timeLastRead = new Date().getTime(); | ||
| setUpRules(null); | ||
| } | ||
|  | ||
| /** | ||
| * Fetches the static instance of ConfigurableRetryLogic, instantiating it if it hasn't already been. | ||
| * Each time the instance is fetched, we check if a re-read is needed, and do so if properties should be re-read. | ||
| * | ||
| * @return The static instance of ConfigurableRetryLogic | ||
| * @throws SQLServerException | ||
| * an exception | ||
| */ | ||
| public static ConfigurableRetryLogic getInstance() throws SQLServerException { | ||
|         
                  Jeffery-Wasty marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| // No need for lock; static initializer singleInstance is thread-safe | ||
| if (singleInstance == null) { | ||
| singleInstance = new ConfigurableRetryLogic(); | ||
| } else { | ||
| refreshRuleSet(); | ||
| } | ||
| return singleInstance; | ||
| } | ||
|  | ||
| /** | ||
| * If it has been INTERVAL_BETWEEN_READS_IN_MS (30 secs) since last read, see if we last did a file read, if so | ||
| * only reread if the file has been modified. If no file read, set up rules using the prev. connection string rules. | ||
| * | ||
| * @throws SQLServerException | ||
| * when an exception occurs | ||
| */ | ||
| private static void refreshRuleSet() throws SQLServerException { | ||
| long currentTime = new Date().getTime(); | ||
| if ((currentTime - timeLastRead) >= INTERVAL_BETWEEN_READS_IN_MS) { | ||
| timeLastRead = currentTime; | ||
| if (timeLastModified != 0) { | ||
| // If timeLastModified has been set, we have previously read from a file, so we setUpRules | ||
| // reading from file | ||
| File f = new File(getCurrentClassPath()); | ||
| if (f.lastModified() != timeLastModified) { | ||
| setUpRules(null); | ||
| } | ||
| } else { | ||
| setUpRules(prevRulesFromConnectionString); | ||
| } | ||
| } | ||
| } | ||
|  | ||
| void setFromConnectionString(String newRules) throws SQLServerException { | ||
| prevRulesFromConnectionString = newRules; | ||
| setUpRules(prevRulesFromConnectionString); | ||
| } | ||
|  | ||
| void storeLastQuery(String newQueryToStore) { | ||
| lastQuery = newQueryToStore.toLowerCase(); | ||
| } | ||
|  | ||
| String getLastQuery() { | ||
| return lastQuery; | ||
| } | ||
|  | ||
| /** | ||
| * Sets up rules based on either connection string option or file read. | ||
| * | ||
| * @param cxnStrRules | ||
| * If null, rules are constructed from file, else, this parameter is used to construct rules | ||
| * @throws SQLServerException | ||
| * If an exception occurs | ||
| */ | ||
| private static void setUpRules(String cxnStrRules) throws SQLServerException { | ||
| stmtRules = new HashMap<>(); | ||
| lastQuery = ""; | ||
| LinkedList<String> temp; | ||
|  | ||
| if (cxnStrRules == null || cxnStrRules.isEmpty()) { | ||
| temp = readFromFile(); | ||
| } else { | ||
| temp = new LinkedList<>(); | ||
| Collections.addAll(temp, cxnStrRules.split(SEMI_COLON)); | ||
| } | ||
| createRules(temp); | ||
| } | ||
|  | ||
| private static void createRules(LinkedList<String> listOfRules) throws SQLServerException { | ||
| stmtRules = new HashMap<>(); | ||
|  | ||
| for (String potentialRule : listOfRules) { | ||
| ConfigurableRetryRule rule = new ConfigurableRetryRule(potentialRule); | ||
|  | ||
| if (rule.getError().contains(COMMA)) { | ||
| String[] arr = rule.getError().split(COMMA); | ||
|  | ||
| for (String retryError : arr) { | ||
| ConfigurableRetryRule splitRule = new ConfigurableRetryRule(retryError, rule); | ||
| stmtRules.put(Integer.parseInt(splitRule.getError()), splitRule); | ||
| } | ||
| } else { | ||
| stmtRules.put(Integer.parseInt(rule.getError()), rule); | ||
| } | ||
| } | ||
| } | ||
|  | ||
| private static String getCurrentClassPath() throws SQLServerException { | ||
| String location = ""; | ||
| String className = ""; | ||
|  | ||
| try { | ||
| className = new Object() {}.getClass().getEnclosingClass().getName(); | ||
| location = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath(); | ||
| location = location.substring(0, location.length() - 16); | ||
| URI uri = new URI(location + FORWARD_SLASH); | ||
| return uri.getPath() + DEFAULT_PROPS_FILE; // For now, we only allow "mssql-jdbc.properties" as file name. | ||
| } catch (URISyntaxException e) { | ||
| MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_URLInvalid")); | ||
| Object[] msgArgs = {location + FORWARD_SLASH}; | ||
| throw new SQLServerException(form.format(msgArgs), null, 0, e); | ||
| } catch (ClassNotFoundException e) { | ||
| MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnableToFindClass")); | ||
| Object[] msgArgs = {className}; | ||
| throw new SQLServerException(form.format(msgArgs), null, 0, e); | ||
| } | ||
| } | ||
|  | ||
| private static LinkedList<String> readFromFile() throws SQLServerException { | ||
| String filePath = getCurrentClassPath(); | ||
| LinkedList<String> list = new LinkedList<>(); | ||
|  | ||
| try { | ||
| File f = new File(filePath); | ||
| try (BufferedReader buffer = new BufferedReader(new FileReader(f))) { | ||
| String readLine; | ||
| while ((readLine = buffer.readLine()) != null) { | ||
| if (readLine.startsWith(RETRY_EXEC)) { | ||
| String value = readLine.split(EQUALS_SIGN)[1]; | ||
| Collections.addAll(list, value.split(SEMI_COLON)); | ||
| } | ||
| } | ||
| } | ||
| timeLastModified = f.lastModified(); | ||
| } catch (FileNotFoundException e) { | ||
| // If the file is not found either A) We're not using CRL OR B) the path is wrong. Do not error out, instead | ||
| // log a message. | ||
| if (CONFIGURABLE_RETRY_LOGGER.isLoggable(java.util.logging.Level.FINER)) { | ||
| CONFIGURABLE_RETRY_LOGGER.finest("File not found at path - \"" + filePath + "\""); | ||
| } | ||
| } catch (IOException e) { | ||
| MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream")); | ||
| Object[] msgArgs = {e.getMessage() + ", from path - \"" + filePath + "\""}; | ||
| throw new SQLServerException(form.format(msgArgs), null, 0, e); | ||
| } | ||
|         
                  Jeffery-Wasty marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| return list; | ||
| } | ||
|  | ||
| ConfigurableRetryRule searchRuleSet(int ruleToSearchFor) throws SQLServerException { | ||
| refreshRuleSet(); | ||
|         
                  Jeffery-Wasty marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| for (Map.Entry<Integer, ConfigurableRetryRule> entry : stmtRules.entrySet()) { | ||
| if (entry.getKey() == ruleToSearchFor) { | ||
| return entry.getValue(); | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
      
      Oops, something went wrong.
        
    
  
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.