1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.http.impl.client.cache;
28
29 import java.util.Map;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentMap;
32
33 import org.apache.http.annotation.Contract;
34 import org.apache.http.annotation.ThreadingBehavior;
35
36
37
38
39
40
41
42 @Contract(threading = ThreadingBehavior.SAFE)
43 public class DefaultFailureCache implements FailureCache {
44
45 static final int DEFAULT_MAX_SIZE = 1000;
46 static final int MAX_UPDATE_TRIES = 10;
47
48 private final int maxSize;
49 private final ConcurrentMap<String, FailureCacheValue> storage;
50
51
52
53
54
55 public DefaultFailureCache() {
56 this(DEFAULT_MAX_SIZE);
57 }
58
59
60
61
62
63 public DefaultFailureCache(final int maxSize) {
64 this.maxSize = maxSize;
65 this.storage = new ConcurrentHashMap<String, FailureCacheValue>();
66 }
67
68 @Override
69 public int getErrorCount(final String identifier) {
70 if (identifier == null) {
71 throw new IllegalArgumentException("identifier may not be null");
72 }
73 final FailureCacheValue storedErrorCode = storage.get(identifier);
74 return storedErrorCode != null ? storedErrorCode.getErrorCount() : 0;
75 }
76
77 @Override
78 public void resetErrorCount(final String identifier) {
79 if (identifier == null) {
80 throw new IllegalArgumentException("identifier may not be null");
81 }
82 storage.remove(identifier);
83 }
84
85 @Override
86 public void increaseErrorCount(final String identifier) {
87 if (identifier == null) {
88 throw new IllegalArgumentException("identifier may not be null");
89 }
90 updateValue(identifier);
91 removeOldestEntryIfMapSizeExceeded();
92 }
93
94 private void updateValue(final String identifier) {
95
96
97
98
99
100
101
102
103
104 for (int i = 0; i < MAX_UPDATE_TRIES; i++) {
105 final FailureCacheValue oldValue = storage.get(identifier);
106 if (oldValue == null) {
107 final FailureCacheValueailureCacheValue.html#FailureCacheValue">FailureCacheValue newValue = new FailureCacheValue(identifier, 1);
108 if (storage.putIfAbsent(identifier, newValue) == null) {
109 return;
110 }
111 }
112 else {
113 final int errorCount = oldValue.getErrorCount();
114 if (errorCount == Integer.MAX_VALUE) {
115 return;
116 }
117 final FailureCacheValueailureCacheValue.html#FailureCacheValue">FailureCacheValue newValue = new FailureCacheValue(identifier, errorCount + 1);
118 if (storage.replace(identifier, oldValue, newValue)) {
119 return;
120 }
121 }
122 }
123 }
124
125 private void removeOldestEntryIfMapSizeExceeded() {
126 if (storage.size() > maxSize) {
127 final FailureCacheValue valueWithOldestTimestamp = findValueWithOldestTimestamp();
128 if (valueWithOldestTimestamp != null) {
129 storage.remove(valueWithOldestTimestamp.getKey(), valueWithOldestTimestamp);
130 }
131 }
132 }
133
134 private FailureCacheValue findValueWithOldestTimestamp() {
135 long oldestTimestamp = Long.MAX_VALUE;
136 FailureCacheValue oldestValue = null;
137 for (final Map.Entry<String, FailureCacheValue> storageEntry : storage.entrySet()) {
138 final FailureCacheValue value = storageEntry.getValue();
139 final long creationTimeInNanos = value.getCreationTimeInNanos();
140 if (creationTimeInNanos < oldestTimestamp) {
141 oldestTimestamp = creationTimeInNanos;
142 oldestValue = storageEntry.getValue();
143 }
144 }
145 return oldestValue;
146 }
147 }