|
35 | 35 | import org.eclipse.rdf4j.model.vocabulary.XSD; |
36 | 36 | import org.eclipse.rdf4j.sail.SailException; |
37 | 37 | import org.eclipse.rdf4j.sail.nativerdf.datastore.DataStore; |
| 38 | +import org.eclipse.rdf4j.sail.nativerdf.datastore.RecoveredDataException; |
38 | 39 | import org.eclipse.rdf4j.sail.nativerdf.model.CorruptIRI; |
39 | 40 | import org.eclipse.rdf4j.sail.nativerdf.model.CorruptIRIOrBNode; |
40 | 41 | import org.eclipse.rdf4j.sail.nativerdf.model.CorruptLiteral; |
@@ -145,7 +146,7 @@ public ValueStore(File dataDir, boolean forceSync) throws IOException { |
145 | 146 | public ValueStore(File dataDir, boolean forceSync, int valueCacheSize, int valueIDCacheSize, int namespaceCacheSize, |
146 | 147 | int namespaceIDCacheSize) throws IOException { |
147 | 148 | super(); |
148 | | - dataStore = new DataStore(dataDir, FILENAME_PREFIX, forceSync); |
| 149 | + dataStore = new DataStore(dataDir, FILENAME_PREFIX, forceSync, this); |
149 | 150 |
|
150 | 151 | valueCache = new ConcurrentCache<>(valueCacheSize); |
151 | 152 | valueIDCache = new ConcurrentCache<>(valueIDCacheSize); |
@@ -194,15 +195,31 @@ public NativeValue getValue(int id) throws IOException { |
194 | 195 | NativeValue resultValue = valueCache.get(cacheID); |
195 | 196 |
|
196 | 197 | if (resultValue == null) { |
197 | | - // Value not in cache, fetch it from file |
198 | | - byte[] data = dataStore.getData(id); |
199 | | - |
200 | | - if (data != null) { |
201 | | - resultValue = data2value(id, data); |
202 | | - |
203 | | - if (!(resultValue instanceof CorruptValue)) { |
204 | | - // Store value in cache |
205 | | - valueCache.put(cacheID, resultValue); |
| 198 | + try { |
| 199 | + // Value not in cache, fetch it from file |
| 200 | + byte[] data = dataStore.getData(id); |
| 201 | + if (data != null) { |
| 202 | + resultValue = data2value(id, data); |
| 203 | + if (!(resultValue instanceof CorruptValue)) { |
| 204 | + // Store value in cache |
| 205 | + valueCache.put(cacheID, resultValue); |
| 206 | + } |
| 207 | + } |
| 208 | + } catch (RecoveredDataException rde) { |
| 209 | + byte[] recovered = rde.getData(); |
| 210 | + if (recovered != null && recovered.length > 0) { |
| 211 | + byte t = recovered[0]; |
| 212 | + if (t == URI_VALUE) { |
| 213 | + resultValue = new CorruptIRI(revision, id, null, recovered); |
| 214 | + } else if (t == BNODE_VALUE) { |
| 215 | + resultValue = new CorruptIRIOrBNode(revision, id, recovered); |
| 216 | + } else if (t == LITERAL_VALUE) { |
| 217 | + resultValue = new CorruptLiteral(revision, id, recovered); |
| 218 | + } else { |
| 219 | + resultValue = new CorruptUnknownValue(revision, id, recovered); |
| 220 | + } |
| 221 | + } else { |
| 222 | + resultValue = new CorruptUnknownValue(revision, id, recovered); |
206 | 223 | } |
207 | 224 | } |
208 | 225 | } |
@@ -434,21 +451,30 @@ public void close() throws IOException { |
434 | 451 | public void checkConsistency() throws SailException, IOException { |
435 | 452 | int maxID = dataStore.getMaxID(); |
436 | 453 | for (int id = 1; id <= maxID; id++) { |
437 | | - byte[] data = dataStore.getData(id); |
438 | | - if (isNamespaceData(data)) { |
439 | | - String namespace = data2namespace(data); |
440 | | - try { |
441 | | - if (id == getNamespaceID(namespace, false) |
442 | | - && java.net.URI.create(namespace + "part").isAbsolute()) { |
443 | | - continue; |
| 454 | + try { |
| 455 | + byte[] data = dataStore.getData(id); |
| 456 | + if (isNamespaceData(data)) { |
| 457 | + String namespace = data2namespace(data); |
| 458 | + try { |
| 459 | + if (id == getNamespaceID(namespace, false) |
| 460 | + && java.net.URI.create(namespace + "part").isAbsolute()) { |
| 461 | + continue; |
| 462 | + } |
| 463 | + } catch (IllegalArgumentException e) { |
| 464 | + // throw SailException |
| 465 | + } |
| 466 | + throw new SailException( |
| 467 | + "Store must be manually exported and imported to fix namespaces like " + namespace); |
| 468 | + } else { |
| 469 | + Value value = this.data2value(id, data); |
| 470 | + if (id != this.getID(copy(value))) { |
| 471 | + throw new SailException( |
| 472 | + "Store must be manually exported and imported to merge values like " + value); |
444 | 473 | } |
445 | | - } catch (IllegalArgumentException e) { |
446 | | - // throw SailException |
447 | 474 | } |
448 | | - throw new SailException( |
449 | | - "Store must be manually exported and imported to fix namespaces like " + namespace); |
450 | | - } else { |
451 | | - Value value = this.data2value(id, data); |
| 475 | + } catch (RecoveredDataException rde) { |
| 476 | + // Treat as a corrupt unknown value during consistency check |
| 477 | + Value value = new CorruptUnknownValue(revision, id, rde.getData()); |
452 | 478 | if (id != this.getID(copy(value))) { |
453 | 479 | throw new SailException( |
454 | 480 | "Store must be manually exported and imported to merge values like " + value); |
@@ -584,7 +610,8 @@ private boolean isNamespaceData(byte[] data) { |
584 | 610 | return data[0] != URI_VALUE && data[0] != BNODE_VALUE && data[0] != LITERAL_VALUE; |
585 | 611 | } |
586 | 612 |
|
587 | | - private NativeValue data2value(int id, byte[] data) throws IOException { |
| 613 | + @InternalUseOnly |
| 614 | + public NativeValue data2value(int id, byte[] data) throws IOException { |
588 | 615 | if (data.length == 0) { |
589 | 616 | if (SOFT_FAIL_ON_CORRUPT_DATA_AND_REPAIR_INDEXES) { |
590 | 617 | logger.error("Soft fail on corrupt data: Empty data array for value with id {}", id); |
@@ -704,8 +731,12 @@ private String getNamespace(int id) throws IOException { |
704 | 731 | String namespace = namespaceCache.get(cacheID); |
705 | 732 |
|
706 | 733 | if (namespace == null) { |
707 | | - byte[] namespaceData = dataStore.getData(id); |
708 | | - namespace = data2namespace(namespaceData); |
| 734 | + try { |
| 735 | + byte[] namespaceData = dataStore.getData(id); |
| 736 | + namespace = data2namespace(namespaceData); |
| 737 | + } catch (RecoveredDataException rde) { |
| 738 | + namespace = data2namespace(rde.getData()); |
| 739 | + } |
709 | 740 |
|
710 | 741 | namespaceCache.put(cacheID, namespace); |
711 | 742 | } |
@@ -829,13 +860,18 @@ public static void main(String[] args) throws Exception { |
829 | 860 |
|
830 | 861 | int maxID = valueStore.dataStore.getMaxID(); |
831 | 862 | for (int id = 1; id <= maxID; id++) { |
832 | | - byte[] data = valueStore.dataStore.getData(id); |
833 | | - if (valueStore.isNamespaceData(data)) { |
834 | | - String ns = valueStore.data2namespace(data); |
835 | | - System.out.println("[" + id + "] " + ns); |
836 | | - } else { |
837 | | - Value value = valueStore.data2value(id, data); |
838 | | - System.out.println("[" + id + "] " + value.toString()); |
| 863 | + try { |
| 864 | + byte[] data = valueStore.dataStore.getData(id); |
| 865 | + if (valueStore.isNamespaceData(data)) { |
| 866 | + String ns = valueStore.data2namespace(data); |
| 867 | + System.out.println("[" + id + "] " + ns); |
| 868 | + } else { |
| 869 | + Value value = valueStore.data2value(id, data); |
| 870 | + System.out.println("[" + id + "] " + value.toString()); |
| 871 | + } |
| 872 | + } catch (RecoveredDataException rde) { |
| 873 | + System.out.println("[" + id + "] CorruptUnknownValue:" |
| 874 | + + new CorruptUnknownValue(valueStore.revision, id, rde.getData())); |
839 | 875 | } |
840 | 876 | } |
841 | 877 | } |
|
0 commit comments