Ticket #23584: 23584-2.patch
| File 23584-2.patch, 13.1 KB (added by , 2 years ago) |
|---|
-
src/reverter/ChangesetReverter.java
4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 import static org.openstreetmap.josm.tools.I18n.trn; 6 6 7 import java.net.HttpURLConnection;8 7 import java.util.ArrayList; 9 8 import java.util.Arrays; 10 9 import java.util.Collection; … … 46 45 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 47 46 import org.openstreetmap.josm.gui.util.GuiHelper; 48 47 import org.openstreetmap.josm.io.MultiFetchServerObjectReader; 49 import org.openstreetmap.josm.io.OsmApiException;50 48 import org.openstreetmap.josm.io.OsmServerChangesetReader; 51 49 import org.openstreetmap.josm.io.OsmTransferException; 52 import org.openstreetmap.josm.tools.Logging;53 50 54 51 /** 55 52 * Fetches and stores data for reverting of specific changeset. … … 203 200 addMissingHistoryIds(deleted); 204 201 } 205 202 206 private static void readObjectVersion(OsmServerMultiObjectReader rdr, PrimitiveId id, int version, ProgressMonitor progressMonitor)207 throws OsmTransferException {208 boolean readOK = false;209 while (!readOK && version >= 1) {210 try {211 rdr.readObject(id, version, progressMonitor.createSubTaskMonitor(1, true));212 readOK = true;213 } catch (OsmApiException e) {214 if (e.getResponseCode() != HttpURLConnection.HTTP_FORBIDDEN) {215 throw e;216 }217 String message = "Version " + version + " of " + id + " is unauthorized";218 Logging.info(version <= 1 ? message : message + ", requesting previous one");219 version--;220 }221 }222 if (!readOK) {223 Logging.warn("Cannot retrieve any previous version of "+id);224 }225 }226 227 203 /** 228 204 * fetch objects that were updated or deleted by changeset 229 205 * @param progressMonitor progress monitor … … 237 213 addChangesetIdPrefix( 238 214 trn("Downloading history for {0} object", "Downloading history for {0} objects", num, num)), num + 1); 239 215 try { 240 HashMap<Long, Integer> nodeList = new HashMap<>() ,241 wayList = new HashMap<>(),242 relationList = new HashMap<>();216 HashMap<Long, Integer> nodeList = new HashMap<>(); 217 HashMap<Long, Integer> wayList = new HashMap<>(); 218 HashMap<Long, Integer> relationList = new HashMap<>(); 243 219 244 220 for (HashSet<HistoryOsmPrimitive> collection : Arrays.asList(updated, deleted)) { 245 221 for (HistoryOsmPrimitive entry : collection) { … … 255 231 } 256 232 } 257 233 } 258 rdr.readMultiObjects (OsmPrimitiveType.NODE, nodeList, progressMonitor);259 rdr.readMultiObjects (OsmPrimitiveType.WAY, wayList, progressMonitor);260 rdr.readMultiObjects (OsmPrimitiveType.RELATION, relationList, progressMonitor);234 rdr.readMultiObjectsOrNextOlder(OsmPrimitiveType.NODE, nodeList, progressMonitor); 235 rdr.readMultiObjectsOrNextOlder(OsmPrimitiveType.WAY, wayList, progressMonitor); 236 rdr.readMultiObjectsOrNextOlder(OsmPrimitiveType.RELATION, relationList, progressMonitor); 261 237 if (progressMonitor.isCanceled()) return; 262 // If multi-read failed, retry with regular read263 for (Map.Entry<Long, Integer> entry : nodeList.entrySet()) {264 if (progressMonitor.isCanceled()) return;265 readObjectVersion(rdr, new SimplePrimitiveId(entry.getKey(), OsmPrimitiveType.NODE), entry.getValue(), progressMonitor);266 }267 for (Map.Entry<Long, Integer> entry : wayList.entrySet()) {268 if (progressMonitor.isCanceled()) return;269 readObjectVersion(rdr, new SimplePrimitiveId(entry.getKey(), OsmPrimitiveType.WAY), entry.getValue(), progressMonitor);270 }271 for (Map.Entry<Long, Integer> entry : relationList.entrySet()) {272 if (progressMonitor.isCanceled()) return;273 readObjectVersion(rdr, new SimplePrimitiveId(entry.getKey(), OsmPrimitiveType.RELATION), entry.getValue(), progressMonitor);274 }275 if (progressMonitor.isCanceled()) return;276 238 nds = rdr.parseOsm(progressMonitor.createSubTaskMonitor(1, true)); 277 239 ds.update(() -> { 278 240 for (OsmPrimitive p : nds.allPrimitives()) { … … 512 474 513 475 // Remove primitives where we already know the LatLon. 514 476 nodes.removeIf(n -> { 477 if (n.isDeleted() || n.isLatLonKnown()) 478 return true; 515 479 PrimitiveId id = n.getPrimitiveId(); 516 480 OsmPrimitive p = ds.getPrimitiveById(id); 517 return !(p instanceof Node) || ((Node) p).isLatLonKnown() ;481 return !(p instanceof Node) || ((Node) p).isLatLonKnown() || p.getVersion() <= 1; 518 482 }); 483 519 484 progressMonitor.worked(num - nodes.size()); 520 485 521 486 // Do bulk version fetches first … … 523 488 final Map<Long, Integer> versionMap = nodes.stream() 524 489 .collect(Collectors.toMap(AbstractPrimitive::getUniqueId, 525 490 id -> Math.max(1, Optional.ofNullable(ds.getPrimitiveById(id)).orElse(id).getVersion() - 1))); 491 526 492 try { 527 493 while (!versionMap.isEmpty()) { 528 494 final OsmServerMultiObjectReader rds = new OsmServerMultiObjectReader(); 529 495 final ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(num, false); 530 496 subMonitor.beginTask(tr("Fetching multi-objects"), versionMap.size()); 531 rds.readMultiObjects (OsmPrimitiveType.NODE, versionMap, subMonitor);497 rds.readMultiObjectsOrNextOlder(OsmPrimitiveType.NODE, versionMap, subMonitor); 532 498 subMonitor.finishTask(); 533 499 final DataSet history = rds.parseOsm(progressMonitor.createSubTaskMonitor(0, false)); 500 ds.update(() -> updateNodes(progressMonitor, nodes, versionMap, history)); 501 versionMap.values().removeIf(i -> i <= 1); 534 502 versionMap.replaceAll((key, value) -> value - 1); 535 versionMap.values().removeIf(i -> i <= 0);536 ds.update(() -> updateNodes(progressMonitor, nodes, versionMap, history));537 503 if (progressMonitor.isCanceled()) { 538 504 break; 539 505 } … … 554 520 for (Node n : nodes) { 555 521 if (!n.isDeleted() && !n.isLatLonKnown()) { 556 522 final Node historyNode = (Node) history.getPrimitiveById(n); 557 if (historyNode != null && historyNode.isLatLonKnown() 558 && changeset.getClosedAt().isAfter(historyNode.getInstant())) { 559 n.load(historyNode.save()); 560 versionMap.remove(n.getUniqueId()); 561 progressMonitor.worked(1); 523 if (historyNode != null) { 524 if (historyNode.isLatLonKnown() 525 && changeset.getClosedAt().isAfter(historyNode.getInstant())) { 526 n.load(historyNode.save()); 527 progressMonitor.worked(1); 528 } else { 529 versionMap.put(n.getId(), historyNode.getVersion()); 530 } 562 531 } 563 532 } 564 533 if (progressMonitor.isCanceled()) { -
src/reverter/OsmServerMultiObjectReader.java
5 5 6 6 import java.io.IOException; 7 7 import java.io.InputStream; 8 import java.net.HttpURLConnection; 8 9 import java.util.ArrayList; 9 10 import java.util.List; 10 11 import java.util.Map; … … 15 16 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 16 17 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 17 18 import org.openstreetmap.josm.io.IllegalDataException; 19 import org.openstreetmap.josm.io.OsmApiException; 18 20 import org.openstreetmap.josm.io.OsmServerReader; 19 21 import org.openstreetmap.josm.io.OsmTransferException; 20 22 import org.openstreetmap.josm.tools.Logging; … … 49 51 * @param list The map of ids to versions 50 52 * @return The queries to make 51 53 */ 52 private static List<String> makeQueryStrings(OsmPrimitiveType type, Map<Long, Integer> list) {54 private static List<String> makeQueryStrings(OsmPrimitiveType type, Map<Long, Integer> list) { 53 55 // This is a "worst-case" calculation. Keep it fast (and err higher rather than lower), not accurate. 54 56 final int expectedSize = (int) (list.entrySet().stream().mapToLong(entry -> 55 57 // Keep in mind that 0-3 is 0, 3-32 is 1, 32-316 is 2, and so on when rounding log10. … … 62 64 ).sum() / MAX_QUERY_LENGTH); 63 65 List<String> result = new ArrayList<>(expectedSize + 1); 64 66 StringBuilder sb = new StringBuilder(); 65 int cnt =0;66 for (Map.Entry<Long, Integer> entry : list.entrySet()) {67 int cnt = 0; 68 for (Map.Entry<Long, Integer> entry : list.entrySet()) { 67 69 if (cnt == 0) { 68 70 sb.append(type.getAPIName()); 69 71 sb.append("s?"); … … 82 84 cnt = 0; 83 85 } 84 86 } 85 if (cnt >0) {87 if (cnt > 0) { 86 88 result.add(sb.toString()); 87 89 } 88 90 return result; … … 108 110 protected static final int MAX_QUERY_LENGTH = 8000; 109 111 110 112 /** 111 * Parse many objects 113 * Parse many objects. 112 114 * @param type The object type (<i>must</i> be common between all objects) 113 * @param list The map of object id to object version 115 * @param list The map of object id to object version. Successfully retrieved objects are removed. 114 116 * @param progressMonitor The progress monitor to update 115 117 * @throws OsmTransferException If there is an issue getting the data 116 118 */ 117 public void readMultiObjects(OsmPrimitiveType type, Map<Long, Integer> list, ProgressMonitor progressMonitor) throws OsmTransferException {118 for (String query : makeQueryStrings(type, list)) {119 public void readMultiObjects(OsmPrimitiveType type, Map<Long, Integer> list, ProgressMonitor progressMonitor) throws OsmTransferException { 120 for (String query : makeQueryStrings(type, list)) { 119 121 if (progressMonitor.isCanceled()) { 120 122 return; 121 123 } … … 129 131 } catch (IOException | IllegalDataException e) { 130 132 Logging.warn(e); 131 133 throw new OsmTransferException(e); 134 } catch (OsmApiException e) { 135 Logging.warn(e); 136 // allow to continue further bulk requests 137 if (e.getResponseCode() != HttpURLConnection.HTTP_FORBIDDEN 138 && e.getResponseCode() != HttpURLConnection.HTTP_NOT_FOUND) { 139 throw e; 140 } 132 141 } finally { 133 142 rdr.callback = null; 134 143 } … … 135 144 } 136 145 } 137 146 147 /** 148 * Parse many objects. If redacted elements are requested the method tries to retrieve the next older version. 149 * @param type The object type (<i>must</i> be common between all objects) 150 * @param list The map of object id to object version. Successfully retrieved objects are removed. 151 * @param progressMonitor The progress monitor to update 152 * @throws OsmTransferException If there is an issue getting the data 153 */ 154 public void readMultiObjectsOrNextOlder(OsmPrimitiveType type, Map<Long, Integer> list, 155 ProgressMonitor progressMonitor) throws OsmTransferException { 156 readMultiObjects(type, list, progressMonitor); 157 // If multi-read failed, retry with regular read 158 for (Map.Entry<Long, Integer> entry : list.entrySet()) { 159 if (progressMonitor.isCanceled()) return; 160 readObjectVersion(type, entry.getKey(), entry.getValue(), progressMonitor); 161 } 162 } 138 163 164 private void readObjectVersion(OsmPrimitiveType type, long id, int version, ProgressMonitor progressMonitor) 165 throws OsmTransferException { 166 boolean readOK = false; 167 while (!readOK && version >= 1) { 168 try { 169 readObject(id, version, type, progressMonitor.createSubTaskMonitor(1, true)); 170 readOK = true; 171 } catch (OsmApiException e) { 172 if (e.getResponseCode() != HttpURLConnection.HTTP_FORBIDDEN) { 173 throw e; 174 } 175 String message = "Version " + version + " of " + id + " is unauthorized"; 176 Logging.info(version <= 1 ? message : message + ", requesting previous one"); 177 version--; 178 } 179 } 180 if (!readOK) { 181 Logging.warn("Cannot retrieve any previous version of {1} {2}", type, id); 182 } 183 } 184 185 139 186 /** 140 187 * Method to parse downloaded objects 141 188 * @return the data requested
