Author: amitj
Date: Wed Jan 27 08:21:41 2016
New Revision: 1726952
URL: http://svn.apache.org/viewvc?rev=1726952&view=rev
Log:
OAK-3184: Consistency checker for data/blob store
Merged revision(s) 1702371, 1702426, 1702428 from trunk
Added:
jackrabbit/oak/branches/1.2/oak-commons/src/test/resources/org/apache/jackrabbit/oak/commons/sort/test-file-2.csv
- copied unchanged from r1702426,
jackrabbit/oak/trunk/oak-commons/src/test/resources/org/apache/jackrabbit/oak/commons/sort/test-file-2.csv
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ReferencedBlob.java
- copied unchanged from r1702371,
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ReferencedBlob.java
Modified:
jackrabbit/oak/branches/1.2/ (props changed)
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/sort/ExternalSort.java
jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/sort/ExternalSortTest.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/GarbageCollectorFileState.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ReferenceCollector.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/InMemoryDataRecord.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobCollector.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIterator.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentBlobReferenceRetriever.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoBlobReferenceIterator.java
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/FileLineDifferenceIteratorTest.java
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobCollectorTest.java
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIteratorTest.java
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceTest.java
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoBlobGCTest.java
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/ExternalBlobTest.java
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentDataStoreBlobGCTest.java
Propchange: jackrabbit/oak/branches/1.2/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Jan 27 08:21:41 2016
@@ -1,3 +1,3 @@
/jackrabbit/oak/branches/1.0:1665962
-/jackrabbit/oak/trunk:1672350,1672468,1672537,1672603,1672642,1672644,1672834-1672835,1673351,1673410,1673414-1673415,1673436,1673644,1673662-1673664,1673669,1673695,1673713,1673738,1673787,1673791,1674046,1674065,1674075,1674107,1674228,1674780,1674880,1675054-1675055,1675319,1675332,1675354,1675357,1675382,1675555,1675566,1675593,1676198,1676237,1676407,1676458,1676539,1676670,1676693,1676703,1676725,1677579,1677581,1677609,1677611,1677774,1677788,1677797,1677804,1677806,1677939,1677991,1678023,1678095-1678096,1678124,1678171,1678173,1678211,1678323,1678758,1678938,1678954,1679144,1679165,1679191,1679232,1679235,1679503,1679958,1679961,1680170,1680172,1680182,1680222,1680232,1680236,1680461,1680633,1680643,1680747,1680805-1680806,1680903,1681282,1681767,1681918,1681921,1681955,1682042,1682218,1682235,1682437,1682494,1682555,1682855,1682904,1683059,1683089,1683213,1683249,1683259,1683278,1683323,1683687,1683700,1684174-1684175,1684186,1684376,1684442,1684561,1684570,1684601,1684618
,1684669,1684820,1684868,1684894,1685023,1685075,1685370,1685552,1685589-1685590,1685840,1685964,1685977,1685989,1685999,1686003,1686023,1686032,1686097,1686162,1686229,1686234,1686253,1686414,1686780,1686854,1686857,1686971,1687053-1687055,1687175,1687196,1687198,1687220,1687239-1687240,1687301,1687441,1687553,1688089-1688090,1688172,1688179,1688349,1688421,1688436,1688453,1688616,1688622,1688634,1688636,1688817,1689003-1689004,1689008,1689577,1689581,1689623,1689810,1689828,1689831,1689833,1689903,1690017,1690043,1690047,1690057,1690247,1690249,1690634-1690637,1690650,1690669,1690674,1690885,1690941,1691139,1691151,1691159,1691167,1691183,1691188,1691210,1691280,1691307,1691331-1691333,1691345,1691384-1691385,1691401,1691509,1692133-1692134,1692156,1692250,1692274,1692363,1692382,1692478,1692955,1693002,1693030,1693050,1693209,1693401,1693421,1693525-1693526,1694007,1694393-1694394,1694651,1694653-1694654,1695032,1695050,1695122,1695280,1695299,1695420,1695457,1695482,1695492,1695
507,1695521,1695540,1695571,1695905,1696190,1696194,1696242,1696285,1696375,1696522,1696578,1696759,1696916,1697363,1697373,1697410,1697582,1697589,1697616,1697672,1700191,1700231,1700397,1700403,1700506,1700571,1700718,1700727,1700749,1700769,1700775,1701065,1701619,1701733,1701743,1701750,1701768,1701806,1701810,1701814,1701907,1701948,1701955,1701959,1701965,1701986,1702014,1702022,1702045,1702051,1702241,1702272,1702387,1702405,1702423,1702860,1702942,1702960,1703212,1703382,1703395,1703411,1703428,1703430,1703568,1703592,1703758,1703858,1703878,1704256,1704282,1704285,1704457,1704479,1704490,1704614,1704629,1704636,1704655,1704670,1704886,1705005,1705027,1705043,1705055,1705250,1705268,1705273,1705323,1705677,1705701,1705871,1705992,1705998,1706009,1706037,1706059,1706212,1706218,1706270,1706764,1706772,1707049,1707191,1707331,1707435,1707509,1708105,1708315,1708546,1708592,1708766,1709012,1709852,1709978,1710013,1710031,1710049,1710205,1710242,1710559,1710575,1710590,1710614,1
710637,1710789,1710800,1710811,1710816,1710972,1711248,1711282,1711296,1711405,1711498,1711654,1712018,1712042,1712319,1712490,1712531,1712730,1712785,1712963,1713008,1713439,1713461,1713580,1713586,1713599-1713600,1713626,1713698,1713803,1713809,1714034,1714061,1714084,1714170,1714213,1714229,1714238,1714519-1714520,1714543-1714544,1714730,1714739,1714779,1714956,1714961,1715010,1715092,1715191,1715346,1715767,1715771,1715888,1715898,1716178,1716426,1716576,1716596,1716616,1716703,1716712,1716815,1716823,1716830,1716883,1717277,1717462,1717632,1717784,1717789,1717988,1718528,1718533,1718547-1718548,1718626,1718646,1718772,1718801-1718802,1718895,1719111,1719288,1719869,1720335,1720350,1720354,1720500,1721160,1721172,1721337,1722141,1722832,1723227,1723239,1723241,1723251,1723254,1723333,1723347,1723350,1723584,1723713,1723731,1724026,1724057,1724186,1724210,1724401,1724628,1724631,1725216,1725477,1725555,1725960,1726232,1726570,1726579,1726585-1726586,1726795,1726797,1726809,172681
2
+/jackrabbit/oak/trunk:1672350,1672468,1672537,1672603,1672642,1672644,1672834-1672835,1673351,1673410,1673414-1673415,1673436,1673644,1673662-1673664,1673669,1673695,1673713,1673738,1673787,1673791,1674046,1674065,1674075,1674107,1674228,1674780,1674880,1675054-1675055,1675319,1675332,1675354,1675357,1675382,1675555,1675566,1675593,1676198,1676237,1676407,1676458,1676539,1676670,1676693,1676703,1676725,1677579,1677581,1677609,1677611,1677774,1677788,1677797,1677804,1677806,1677939,1677991,1678023,1678095-1678096,1678124,1678171,1678173,1678211,1678323,1678758,1678938,1678954,1679144,1679165,1679191,1679232,1679235,1679503,1679958,1679961,1680170,1680172,1680182,1680222,1680232,1680236,1680461,1680633,1680643,1680747,1680805-1680806,1680903,1681282,1681767,1681918,1681921,1681955,1682042,1682218,1682235,1682437,1682494,1682555,1682855,1682904,1683059,1683089,1683213,1683249,1683259,1683278,1683323,1683687,1683700,1684174-1684175,1684186,1684376,1684442,1684561,1684570,1684601,1684618
,1684669,1684820,1684868,1684894,1685023,1685075,1685370,1685552,1685589-1685590,1685840,1685964,1685977,1685989,1685999,1686003,1686023,1686032,1686097,1686162,1686229,1686234,1686253,1686414,1686780,1686854,1686857,1686971,1687053-1687055,1687175,1687196,1687198,1687220,1687239-1687240,1687301,1687441,1687553,1688089-1688090,1688172,1688179,1688349,1688421,1688436,1688453,1688616,1688622,1688634,1688636,1688817,1689003-1689004,1689008,1689577,1689581,1689623,1689810,1689828,1689831,1689833,1689903,1690017,1690043,1690047,1690057,1690247,1690249,1690634-1690637,1690650,1690669,1690674,1690885,1690941,1691139,1691151,1691159,1691167,1691183,1691188,1691210,1691280,1691307,1691331-1691333,1691345,1691384-1691385,1691401,1691509,1692133-1692134,1692156,1692250,1692274,1692363,1692382,1692478,1692955,1693002,1693030,1693050,1693209,1693401,1693421,1693525-1693526,1694007,1694393-1694394,1694651,1694653-1694654,1695032,1695050,1695122,1695280,1695299,1695420,1695457,1695482,1695492,1695
507,1695521,1695540,1695571,1695905,1696190,1696194,1696242,1696285,1696375,1696522,1696578,1696759,1696916,1697363,1697373,1697410,1697582,1697589,1697616,1697672,1700191,1700231,1700397,1700403,1700506,1700571,1700718,1700727,1700749,1700769,1700775,1701065,1701619,1701733,1701743,1701750,1701768,1701806,1701810,1701814,1701907,1701948,1701955,1701959,1701965,1701986,1702014,1702022,1702045,1702051,1702241,1702272,1702371,1702387,1702405,1702423,1702426,1702428,1702860,1702942,1702960,1703212,1703382,1703395,1703411,1703428,1703430,1703568,1703592,1703758,1703858,1703878,1704256,1704282,1704285,1704457,1704479,1704490,1704614,1704629,1704636,1704655,1704670,1704886,1705005,1705027,1705043,1705055,1705250,1705268,1705273,1705323,1705677,1705701,1705871,1705992,1705998,1706009,1706037,1706059,1706212,1706218,1706270,1706764,1706772,1707049,1707191,1707331,1707435,1707509,1708105,1708315,1708546,1708592,1708766,1709012,1709852,1709978,1710013,1710031,1710049,1710205,1710242,1710559,1
710575,1710590,1710614,1710637,1710789,1710800,1710811,1710816,1710972,1711248,1711282,1711296,1711405,1711498,1711654,1712018,1712042,1712319,1712490,1712531,1712730,1712785,1712963,1713008,1713439,1713461,1713580,1713586,1713599-1713600,1713626,1713698,1713803,1713809,1714034,1714061,1714084,1714170,1714213,1714229,1714238,1714519-1714520,1714543-1714544,1714730,1714739,1714779,1714956,1714961,1715010,1715092,1715191,1715346,1715767,1715771,1715888,1715898,1716178,1716426,1716576,1716596,1716616,1716703,1716712,1716815,1716823,1716830,1716883,1717277,1717462,1717632,1717784,1717789,1717988,1718528,1718533,1718547-1718548,1718626,1718646,1718772,1718801-1718802,1718895,1719111,1719288,1719869,1720335,1720350,1720354,1720500,1721160,1721172,1721337,1722141,1722832,1723227,1723239,1723241,1723251,1723254,1723333,1723347,1723350,1723584,1723713,1723731,1724026,1724057,1724186,1724210,1724401,1724628,1724631,1725216,1725477,1725555,1725960,1726232,1726570,1726579,1726585-1726586,172679
5,1726797,1726809,1726812
/jackrabbit/trunk:1345480
Modified:
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/sort/ExternalSort.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/sort/ExternalSort.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/sort/ExternalSort.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/sort/ExternalSort.java
Wed Jan 27 08:21:41 2016
@@ -295,7 +295,7 @@ public class ExternalSort {
try {
for (String r : tmplist) {
// Skip duplicate lines
- if (!distinct || !r.equals(lastLine)) {
+ if (!distinct || (lastLine == null || (lastLine != null &&
cmp.compare(r, lastLine) != 0))) {
writeLine(fbw, r);
fbw.newLine();
lastLine = r;
@@ -453,7 +453,7 @@ public class ExternalSort {
BinaryFileBuffer bfb = pq.poll();
String r = bfb.pop();
// Skip duplicate lines
- if (!distinct || !r.equals(lastLine)) {
+ if (!distinct || (lastLine == null || (lastLine != null &&
cmp.compare(r, lastLine) != 0))) {
writeLine(fbw, r);
fbw.newLine();
lastLine = r;
Modified:
jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/sort/ExternalSortTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/sort/ExternalSortTest.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/sort/ExternalSortTest.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/sort/ExternalSortTest.java
Wed Jan 27 08:21:41 2016
@@ -78,6 +78,8 @@ public class ExternalSortTest {
private static final String TEST_FILE1_TXT = "test-file-1.txt";
private static final String TEST_FILE2_TXT = "test-file-2.txt";
private static final String TEST_FILE1_CSV = "test-file-1.csv";
+ private static final String TEST_FILE2_CSV = "test-file-2.csv";
+
private static final String[] EXPECTED_SORT_RESULTS = { "a", "b", "b", "e",
"f", "i", "m", "o", "u", "u", "x", "y", "z" };
private static final String[] EXPECTED_MERGE_RESULTS = { "a", "a", "b",
@@ -90,10 +92,14 @@ public class ExternalSortTest {
"f", "i", "m", "o", "u", "x", "y", "z" };
private static final String[] SAMPLE = { "f", "m", "b", "e", "i", "o", "u",
"x", "a", "y", "z", "b", "u" };
-
+ private static final String[] EXPECTED_CSV_DISTINCT_RESULTS = { "a,1",
"b,2a", "e,3", "f,4", "i,5", "m,6", "o,7",
+ "u,8a",
"x,9", "y,10", "z,11"};
+ private static final String[] EXPECTED_CSV_RESULTS = { "a,1", "b,2a",
"b,2b", "e,3", "f,4", "i,5", "m,6", "o,7",
+ "u,8a", "u,8b",
"x,9", "y,10", "z,11"};
private File file1;
private File file2;
private File csvFile;
+ private File csvFile2;
private List<File> fileList;
/**
@@ -108,6 +114,8 @@ public class ExternalSortTest {
getResource(TEST_FILE2_TXT).toURI());
this.csvFile = new File(this.getClass().
getResource(TEST_FILE1_CSV).toURI());
+ this.csvFile2 = new File(this.getClass().
+ getResource(TEST_FILE2_CSV).toURI());
File tmpFile1 = new File(this.file1.getPath().toString() + ".tmp");
File tmpFile2 = new File(this.file2.getPath().toString() + ".tmp");
@@ -340,6 +348,51 @@ public class ExternalSortTest {
testCSVSortingWithParams(true);
}
+ @Test
+ public void testCSVKeyValueSorting() throws Exception {
+ testCSVSortKeyValue(false);
+ testCSVSortKeyValue(true);
+ }
+
+ /**
+ * Sample case to sort csv file with key, value pair.
+ *
+ * @param distinct if distinct records need to be omitted
+ * @throws Exception
+ *
+ */
+ public void testCSVSortKeyValue(boolean distinct) throws Exception {
+
+ File out = File.createTempFile("test_results", ".tmp", null);
+
+ Comparator<String> cmp = new Comparator<String>() {
+ @Override
+ public int compare(String s1, String s2) {
+ return s1.split(",")[0].compareTo(s2.split(",")[0]);
+ }
+ };
+
+ List<File> listOfFiles = ExternalSort.sortInBatch(this.csvFile2, cmp,
+
ExternalSort.DEFAULTMAXTEMPFILES,
+
ExternalSort.DEFAULT_MAX_MEM_BYTES,
+
Charset.defaultCharset(),
+ null, distinct,
0, false);
+
+ // now merge with append
+ ExternalSort.mergeSortedFiles(listOfFiles, out, cmp,
+ Charset.defaultCharset(), distinct,
true, false);
+ ArrayList<String> result = readLines(out);
+
+ if (distinct) {
+ assertEquals(11, result.size());
+ assertArrayEquals(Arrays.toString(result.toArray()),
EXPECTED_CSV_DISTINCT_RESULTS, result.toArray());
+ } else {
+ assertEquals(13, result.size());
+ assertArrayEquals(Arrays.toString(result.toArray()),
EXPECTED_CSV_RESULTS, result.toArray());
+ }
+
+ }
+
/**
* Sample case to sort csv file.
*
@@ -404,4 +457,4 @@ public class ExternalSortTest {
}
}
-}
\ No newline at end of file
+}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGC.java
Wed Jan 27 08:21:41 2016
@@ -59,7 +59,11 @@ public class BlobGC extends AnnotatedSt
private final Executor executor;
private ManagementOperation<String> gcOp = done(OP_NAME, "");
-
+
+ public static final String CONSISTENCY_OP_NAME = "Blob consistency check";
+
+ private ManagementOperation<String> consistencyOp =
done(CONSISTENCY_OP_NAME, "");
+
/**
* @param blobGarbageCollector Blob garbage collector
* @param executor executor for running the garbage
collection task
@@ -114,6 +118,30 @@ public class BlobGC extends AnnotatedSt
return tds;
}
+ @Override
+ public CompositeData checkConsistency() {
+ if (consistencyOp.isDone()) {
+ consistencyOp = newManagementOperation(CONSISTENCY_OP_NAME, new
Callable<String>() {
+ @Override
+ public String call() throws Exception {
+ long t0 = nanoTime();
+ long missing = blobGarbageCollector.checkConsistency();
+ return "Consistency check completed in "
+ + formatTime(nanoTime() - t0) + " " +
+ + missing + "missing blobs found (details in
the log).";
+ }
+ });
+ executor.execute(consistencyOp);
+ }
+ return getConsistencyCheckStatus();
+ }
+
+ @Nonnull
+ @Override
+ public CompositeData getConsistencyCheckStatus() {
+ return consistencyOp.getStatus().toCompositeData();
+ }
+
private CompositeDataSupport toCompositeData(GarbageCollectionRepoStats
statObj) throws OpenDataException {
Object[] values = new Object[] {
statObj.getRepositoryId(),
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGCMBean.java
Wed Jan 27 08:21:41 2016
@@ -61,5 +61,20 @@ public interface BlobGCMBean {
* @return List of available repositories and their status
*/
TabularData getGlobalMarkStats();
-
+
+ /**
+ * Data Store consistency check
+ *
+ * @return the missing blobs
+ */
+ CompositeData checkConsistency();
+
+ /**
+ * Consistency check status
+ *
+ * @return the status of the ongoing operation or if none the terminal
+ * status of the last operation or <em>Status not available</em> if none.
+ */
+ @Nonnull
+ CompositeData getConsistencyCheckStatus();
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/BlobGarbageCollector.java
Wed Jan 27 08:21:41 2016
@@ -39,4 +39,12 @@ public interface BlobGarbageCollector {
* @throws Exception
*/
List<GarbageCollectionRepoStats> getStats() throws Exception;
+
+ /**
+ * Checks for consistency in the blob store and reporting the number of
missing blobs.
+ *
+ * @return number of inconsistencies
+ * @throws Exception
+ */
+ long checkConsistency() throws Exception;
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/GarbageCollectorFileState.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/GarbageCollectorFileState.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/GarbageCollectorFileState.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/GarbageCollectorFileState.java
Wed Jan 27 08:21:41 2016
@@ -134,6 +134,20 @@ public class GarbageCollectorFileState i
merge(ExternalSort.sortInBatch(file, lexComparator, true), sorted);
Files.move(sorted, file);
}
+
+ /**
+ * Sorts the given file externally with the given comparator.
+ *
+ * @param file file whose contents needs to be sorted
+ * @param comparator to compare
+ * @throws IOException
+ */
+ public static void sort(File file, Comparator<String> comparator) throws
IOException {
+ File sorted = createTempFile();
+ merge(ExternalSort.sortInBatch(file, comparator, true), sorted);
+ Files.move(sorted, file);
+ }
+
public static void merge(List<File> files, File output) throws IOException
{
ExternalSort.mergeSortedFiles(
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/MarkSweepGarbageCollector.java
Wed Jan 27 08:21:41 2016
@@ -27,12 +27,14 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.sql.Timestamp;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -49,11 +51,13 @@ import com.google.common.collect.Maps;
import com.google.common.collect.PeekingIterator;
import com.google.common.io.Closeables;
import com.google.common.io.Files;
+import com.google.common.util.concurrent.ListenableFutureTask;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.apache.jackrabbit.core.data.DataRecord;
import org.apache.jackrabbit.core.data.DataStoreException;
import org.apache.jackrabbit.oak.commons.IOUtils;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.InMemoryDataRecord;
import org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils;
import
org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils.SharedStoreRecordType;
import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
@@ -80,7 +84,9 @@ public class MarkSweepGarbageCollector i
public static final String TEMP_DIR =
StandardSystemProperty.JAVA_IO_TMPDIR.value();
public static final int DEFAULT_BATCH_COUNT = 2048;
-
+
+ public static final String DELIM = ",";
+
/** The last modified time before current time of blobs to consider for
garbage collection. */
private final long maxLastModifiedInterval;
@@ -286,13 +292,18 @@ public class MarkSweepGarbageCollector i
FileLineDifferenceIterator iter = new FileLineDifferenceIterator(
fs.getMarkedRefs(),
fs.getAvailableRefs());
+ calculateDifference(fs, iter);
+ LOG.debug("Ending difference phase of the garbage collector");
+ }
+
+ private long calculateDifference(GarbageCollectorFileState fs,
FileLineDifferenceIterator iter) throws IOException {
+ long numCandidates = 0;
BufferedWriter bufferWriter = null;
try {
bufferWriter = Files.newWriter(fs.getGcCandidates(),
Charsets.UTF_8);
List<String> expiredSet = newArrayList();
- int numCandidates = 0;
while (iter.hasNext()) {
expiredSet.add(iter.next());
if (expiredSet.size() > getBatchCount()) {
@@ -305,15 +316,14 @@ public class MarkSweepGarbageCollector i
numCandidates += expiredSet.size();
saveBatchToFile(expiredSet, bufferWriter);
}
- LOG.debug("Found GC candidates - " + numCandidates);
+ LOG.debug("Found candidates - " + numCandidates);
} finally {
IOUtils.closeQuietly(bufferWriter);
IOUtils.closeQuietly(iter);
}
-
- LOG.debug("Ending difference phase of the garbage collector");
+ return numCandidates;
}
-
+
/**
* Sweep phase of gc candidate deletion.
* <p>
@@ -480,16 +490,18 @@ public class MarkSweepGarbageCollector i
private final boolean debugMode = LOG.isTraceEnabled();
@Override
- public void addReference(String blobId) {
+ public void addReference(String blobId, String nodeId)
{
if (debugMode) {
- LOG.trace("BlobId : {}", blobId);
+ LOG.trace("BlobId : {}, NodeId : {}", blobId,
nodeId);
}
try {
Iterator<String> idIter =
blobStore.resolveChunks(blobId);
+ Joiner delimJoiner =
Joiner.on(DELIM).skipNulls();
while (idIter.hasNext()) {
String id = idIter.next();
- idBatch.add(id);
+
+ idBatch.add(delimJoiner.join(id, nodeId));
if (idBatch.size() >= getBatchCount()) {
saveBatchToFile(idBatch, writer);
@@ -518,14 +530,67 @@ public class MarkSweepGarbageCollector i
);
LOG.info("Number of valid blob references marked under mark phase
of " +
"Blob garbage collection [{}]", count.get());
- // sort the marked references
- GarbageCollectorFileState.sort(fs.getMarkedRefs());
+ // sort the marked references with the first part of the key
+ GarbageCollectorFileState.sort(fs.getMarkedRefs(),
+ new Comparator<String>() {
+ @Override
+ public int compare(String
s1, String s2) {
+ return
s1.split(DELIM)[0].compareTo(s2.split(DELIM)[0]);
+ }
+ });
} finally {
IOUtils.closeQuietly(writer);
}
}
-
-
+
+ /**
+ * Checks for the DataStore consistency and reports the number of missing
blobs still referenced.
+ *
+ * @return the missing blobs
+ * @throws Exception
+ */
+ @Override
+ public long checkConsistency() throws Exception {
+ boolean threw = true;
+ GarbageCollectorFileState fs = new GarbageCollectorFileState(root);
+ long candidates = 0;
+
+ try {
+ Stopwatch sw = Stopwatch.createStarted();
+ LOG.info("Starting blob consistency check");
+
+ // Find all blobs available in the blob store
+ ListenableFutureTask<Integer> blobIdRetriever =
ListenableFutureTask.create(new BlobIdRetriever(fs));
+ executor.execute(blobIdRetriever);
+
+ // Mark all used blob references
+ iterateNodeTree(fs);
+
+ try {
+ blobIdRetriever.get();
+ } catch (ExecutionException e) {
+ LOG.warn("Error occurred while fetching all the blobIds from
the BlobStore");
+ threw = false;
+ throw e;
+ }
+
+ LOG.trace("Starting difference phase of the consistency check");
+ FileLineDifferenceIterator iter = new
FileLineDifferenceIterator(fs.getAvailableRefs(), fs.getMarkedRefs());
+ candidates = calculateDifference(fs, iter);
+ LOG.trace("Ending difference phase of the consistency check");
+
+ LOG.info("Consistency check found [{}] missing blobs", candidates);
+ if (candidates > 0) {
+ LOG.warn("Consistency check failure in the the blob store :
{}, check missing candidates in file {}",
+ blobStore, fs.getGcCandidates().getAbsolutePath());
+ }
+ } finally {
+ if (!LOG.isTraceEnabled() && candidates == 0) {
+ Closeables.close(fs, threw);
+ }
+ }
+ return candidates;
+ }
/**
* BlobIdRetriever class to retrieve all blob ids.
*/
@@ -564,7 +629,7 @@ public class MarkSweepGarbageCollector i
// sort the file
GarbageCollectorFileState.sort(fs.getAvailableRefs());
- LOG.debug("Number of blobs present in BlobStore : [{}] ",
blobsCount);
+ LOG.info("Number of blobs present in BlobStore : [{}] ",
blobsCount);
} finally {
IOUtils.closeQuietly(bufferWriter);
}
@@ -606,7 +671,11 @@ public class MarkSweepGarbageCollector i
LineIterator.closeQuietly(marked);
LineIterator.closeQuietly(all);
}
-
+
+ private String getKey(String row) {
+ return row.split(DELIM)[0];
+ }
+
private String computeNextDiff() {
if (!all.hasNext()) {
return null;
@@ -622,7 +691,7 @@ public class MarkSweepGarbageCollector i
diff = all.next();
while (peekMarked.hasNext()) {
String marked = peekMarked.peek();
- int comparisonResult = diff.compareTo(marked);
+ int comparisonResult =
getKey(diff).compareTo(getKey(marked));
if (comparisonResult > 0) {
//Extra entries in marked. Ignore them and move on
peekMarked.next();
@@ -635,7 +704,12 @@ public class MarkSweepGarbageCollector i
} else {
//This entry is not found in marked entries
//hence part of diff
- return diff;
+ if (!InMemoryDataRecord.isInstance(getKey(diff))) {
+ return diff;
+ } else {
+ diff = null;
+ break;
+ }
}
}
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ReferenceCollector.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ReferenceCollector.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ReferenceCollector.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ReferenceCollector.java
Wed Jan 27 08:21:41 2016
@@ -18,14 +18,21 @@
*/
package org.apache.jackrabbit.oak.plugins.blob;
+import javax.annotation.Nullable;
+
/**
* Callback interface for collecting all blob references that are
* potentially accessible. Useful for marking referenced blobs as
* in use when collecting garbage in an external data store.
*/
public interface ReferenceCollector {
-
- void addReference(String reference);
-
+
+ /**
+ * Adds the reference detected with the node Id.
+ *
+ * @param reference
+ * @param nodeId
+ */
+ void addReference(String reference, @Nullable String nodeId);
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/InMemoryDataRecord.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/InMemoryDataRecord.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/InMemoryDataRecord.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/datastore/InMemoryDataRecord.java
Wed Jan 27 08:21:41 2016
@@ -31,7 +31,7 @@ import org.slf4j.LoggerFactory;
/**
* Represents binary data which is backed by a byte[] (in memory).
*/
-class InMemoryDataRecord implements DataRecord {
+public class InMemoryDataRecord implements DataRecord {
/**
* Logger instance for this class
@@ -89,7 +89,7 @@ class InMemoryDataRecord implements Data
* @param id DataRecord identifier
* @return true if it can be converted
*/
- static boolean isInstance(String id) {
+ public static boolean isInstance(String id) {
return id.startsWith(PREFIX);
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobCollector.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobCollector.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobCollector.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobCollector.java
Wed Jan 27 08:21:41 2016
@@ -27,6 +27,7 @@ import org.apache.jackrabbit.oak.api.Pro
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.json.JsopReader;
import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
+import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
public class BlobCollector {
@@ -36,7 +37,7 @@ public class BlobCollector {
this.nodeStore = nodeStore;
}
- public void collect(NodeDocument doc, Collection<Blob> blobs) {
+ public void collect(NodeDocument doc, Collection<ReferencedBlob> blobs) {
for (String key : doc.keySet()) {
if (!Utils.isPropertyName(key)) {
continue;
@@ -44,13 +45,13 @@ public class BlobCollector {
Map<Revision, String> valueMap = doc.getLocalMap(key);
for (String v : valueMap.values()) {
if (v != null) {
- loadValue(v, blobs);
+ loadValue(v, blobs, doc.getPath());
}
}
}
}
- private void loadValue(String v, Collection<Blob> blobs) {
+ private void loadValue(String v, Collection<ReferencedBlob> blobs, String
nodeId) {
JsopReader reader = new JsopTokenizer(v);
PropertyState p;
if (reader.matches('[')) {
@@ -58,14 +59,14 @@ public class BlobCollector {
if (p.getType() == Type.BINARIES) {
for (int i = 0; i < p.count(); i++) {
Blob b = p.getValue(Type.BINARY, i);
- blobs.add(b);
+ blobs.add(new ReferencedBlob(b, nodeId));
}
}
} else {
p = DocumentPropertyState.readProperty("x", nodeStore, reader);
if (p.getType() == Type.BINARY) {
Blob b = p.getValue(Type.BINARY);
- blobs.add(b);
+ blobs.add(new ReferencedBlob(b, nodeId));
}
}
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIterator.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIterator.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIterator.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIterator.java
Wed Jan 27 08:21:41 2016
@@ -21,7 +21,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
-import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
/**
* An iterator over all referenced binaries.
@@ -30,13 +30,13 @@ import org.apache.jackrabbit.oak.api.Blo
* The items are returned in no particular order.
* An item might be returned multiple times.
*/
-public class BlobReferenceIterator implements Iterator<Blob> {
+public class BlobReferenceIterator implements Iterator<ReferencedBlob> {
private static final int BATCH_SIZE = 1000;
private final DocumentStore docStore;
private final BlobCollector blobCollector;
- private HashSet<Blob> batch = new HashSet<Blob>();
- private Iterator<Blob> batchIterator;
+ private HashSet<ReferencedBlob> batch = new HashSet<ReferencedBlob>();
+ private Iterator<ReferencedBlob> batchIterator;
private boolean done;
private String fromKey = NodeDocument.MIN_ID_VALUE;
@@ -55,7 +55,7 @@ public class BlobReferenceIterator imple
}
@Override
- public Blob next() {
+ public ReferencedBlob next() {
// this will load the next batch if required
if (!hasNext()) {
throw new NoSuchElementException();
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentBlobReferenceRetriever.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentBlobReferenceRetriever.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentBlobReferenceRetriever.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentBlobReferenceRetriever.java
Wed Jan 27 08:21:41 2016
@@ -26,6 +26,7 @@ import org.apache.jackrabbit.oak.commons
import org.apache.jackrabbit.oak.plugins.blob.BlobReferenceRetriever;
import org.apache.jackrabbit.oak.plugins.blob.BlobStoreBlob;
import org.apache.jackrabbit.oak.plugins.blob.ReferenceCollector;
+import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,23 +44,24 @@ public class DocumentBlobReferenceRetrie
@Override
public void collectReferences(ReferenceCollector collector) {
int referencesFound = 0;
- Iterator<Blob> blobIterator = nodeStore.getReferencedBlobsIterator();
+ Iterator<ReferencedBlob> blobIterator =
nodeStore.getReferencedBlobsIterator();
try {
while (blobIterator.hasNext()) {
- Blob blob = blobIterator.next();
+ ReferencedBlob refBlob = blobIterator.next();
+ Blob blob = refBlob.getBlob();
referencesFound++;
//TODO this mode would also add in memory blobId
//Would that be an issue
if (blob instanceof BlobStoreBlob) {
- collector.addReference(((BlobStoreBlob) blob).getBlobId());
+ collector.addReference(((BlobStoreBlob) blob).getBlobId(),
refBlob.getId());
} else {
//TODO Should not rely on toString. Instead obtain
//secure reference and convert that to blobId using
//blobStore
- collector.addReference(blob.toString());
+ collector.addReference(blob.toString(), refBlob.getId());
}
}
}finally{
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
Wed Jan 27 08:21:41 2016
@@ -82,6 +82,7 @@ import org.apache.jackrabbit.oak.commons
import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
import org.apache.jackrabbit.oak.plugins.blob.BlobStoreBlob;
import org.apache.jackrabbit.oak.plugins.blob.MarkSweepGarbageCollector;
+import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
import org.apache.jackrabbit.oak.plugins.document.Checkpoints.Info;
import org.apache.jackrabbit.oak.plugins.document.cache.CacheInvalidationStats;
import
org.apache.jackrabbit.oak.plugins.document.mongo.MongoBlobReferenceIterator;
@@ -2608,7 +2609,7 @@ public final class DocumentNodeStore
* @see
org.apache.jackrabbit.oak.plugins.document.mongo.MongoBlobReferenceIterator
* @return an iterator for all the blobs
*/
- public Iterator<Blob> getReferencedBlobsIterator() {
+ public Iterator<ReferencedBlob> getReferencedBlobsIterator() {
if(store instanceof MongoDocumentStore){
return new MongoBlobReferenceIterator(this, (MongoDocumentStore)
store);
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoBlobReferenceIterator.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoBlobReferenceIterator.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoBlobReferenceIterator.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoBlobReferenceIterator.java
Wed Jan 27 08:21:41 2016
@@ -28,16 +28,16 @@ import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
-import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
import org.apache.jackrabbit.oak.plugins.document.BlobCollector;
import org.apache.jackrabbit.oak.plugins.document.Collection;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
-public class MongoBlobReferenceIterator extends AbstractIterator<Blob>
implements Closeable {
+public class MongoBlobReferenceIterator extends
AbstractIterator<ReferencedBlob> implements Closeable {
private final MongoDocumentStore documentStore;
private final BlobCollector blobCollector;
- private final Queue<Blob> blobs = Queues.newArrayDeque();
+ private final Queue<ReferencedBlob> blobs = Queues.newArrayDeque();
private DBCursor cursor;
@@ -48,7 +48,7 @@ public class MongoBlobReferenceIterator
}
@Override
- protected Blob computeNext() {
+ protected ReferencedBlob computeNext() {
if (blobs.isEmpty()) {
loadBatch();
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
Wed Jan 27 08:21:41 2016
@@ -305,7 +305,7 @@ public class Segment {
for (int i = 0; i < blobrefcount; i++) {
int offset = (data.getShort(blobrefpos + i * 2) & 0xffff) << 2;
SegmentBlob blob = new SegmentBlob(new RecordId(id, offset));
- collector.addReference(blob.getBlobId());
+ collector.addReference(blob.getBlobId(), null);
}
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/FileLineDifferenceIteratorTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/FileLineDifferenceIteratorTest.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/FileLineDifferenceIteratorTest.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/FileLineDifferenceIteratorTest.java
Wed Jan 27 08:21:41 2016
@@ -89,7 +89,21 @@ public class FileLineDifferenceIteratorT
assertDiff("a,b,d,e,f", "a,b,c,f, h", asList("c", "h"));
assertDiff("3,7", "2,3,5,9", asList("2", "5", "9"));
}
-
+
+ @Test
+ public void testMarkedDiffWithExtraEntriesInMarked() throws IOException {
+ assertReverseDiff("a,b,c,e,h", "a,b,c", asList("e", "h"));
+ assertReverseDiff("a,b,d,e", "a,b,c", asList("d", "e"));
+ assertReverseDiff("a,b,d", "a,b,d", Collections.<String>emptyList());
+ assertReverseDiff("a,0xb,d,e,f", "a,d", asList("e", "f"));
+ assertReverseDiff("a,0xb,d,e,f", "a,d,e,f,g",
Collections.<String>emptyList());
+ }
+
+ private static void assertReverseDiff(String marked, String all,
List<String> diff) throws IOException {
+ Iterator<String> itr = createItr(all, marked);
+ assertThat("marked: " + marked + " all: " + all,
ImmutableList.copyOf(itr), is(diff));
+ }
+
private static void assertDiff(String marked, String all, List<String>
diff) throws IOException {
Iterator<String> itr = createItr(marked, all);
assertThat("marked: " + marked + " all: " + all,
ImmutableList.copyOf(itr), is(diff));
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobCollectorTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobCollectorTest.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobCollectorTest.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobCollectorTest.java
Wed Jan 27 08:21:41 2016
@@ -25,6 +25,7 @@ import java.util.List;
import com.google.common.collect.Lists;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
@@ -48,7 +49,7 @@ public class BlobCollectorTest {
@Test
public void testCollect() throws Exception {
NodeBuilder b1 = store.getRoot().builder();
- List<Blob> blobs = Lists.newArrayList();
+ List<ReferencedBlob> blobs = Lists.newArrayList();
b1.child("x").child("y");
store.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY);
@@ -58,7 +59,7 @@ public class BlobCollectorTest {
b1 = store.getRoot().builder();
Blob b = store.createBlob(randomStream(i, 4096));
b1.child("x").child("y").setProperty("b" + i, b);
- blobs.add(b);
+ blobs.add(new ReferencedBlob(b, "/x/y"));
store.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY);
}
@@ -68,7 +69,7 @@ public class BlobCollectorTest {
for(int i = 0; i < 2; i++){
Blob b = store.createBlob(randomStream(i, 4096));
p1.addValue(b);
- blobs.add(b);
+ blobs.add(new ReferencedBlob(b, "/x/y"));
}
b1 = store.getRoot().builder();
b1.child("x").child("y").setProperty(p1.getPropertyState());
@@ -80,16 +81,16 @@ public class BlobCollectorTest {
//Change the see to create diff binary
Blob b = store.createBlob(randomStream(i+1, 4096));
b1.child("x").child("y").setProperty("b" + i, b);
- blobs.add(b);
+ blobs.add(new ReferencedBlob(b, "/x/y"));
store.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY);
}
NodeDocument doc =
store.getDocumentStore().find(Collection.NODES,
Utils.getIdFromPath("/x/y"));
- List<Blob> collectedBlobs = Lists.newArrayList();
+ List<ReferencedBlob> collectedBlobs = Lists.newArrayList();
blobCollector.collect(doc, collectedBlobs);
assertEquals(blobs.size(), collectedBlobs.size());
- assertEquals(new HashSet<Blob>(blobs), new
HashSet<Blob>(collectedBlobs));
+ assertEquals(new HashSet<ReferencedBlob>(blobs), new
HashSet<ReferencedBlob>(collectedBlobs));
}
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIteratorTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIteratorTest.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIteratorTest.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceIteratorTest.java
Wed Jan 27 08:21:41 2016
@@ -26,6 +26,7 @@ import java.util.List;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -76,19 +77,19 @@ public class BlobReferenceIteratorTest {
@Test
public void testBlobIterator() throws Exception{
- List<Blob> blobs = Lists.newArrayList();
+ List<ReferencedBlob> blobs = Lists.newArrayList();
//1. Set some single value Binary property
for(int i = 0; i < 10; i++){
NodeBuilder b1 = store.getRoot().builder();
Blob b = store.createBlob(randomStream(i, 4096));
b1.child("x").child("y"+1).setProperty("b" + i, b);
- blobs.add(b);
+ blobs.add(new ReferencedBlob(b, "/x/y" + 1));
store.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY);
}
- List<Blob> collectedBlobs =
ImmutableList.copyOf(store.getReferencedBlobsIterator());
+ List<ReferencedBlob> collectedBlobs =
ImmutableList.copyOf(store.getReferencedBlobsIterator());
assertEquals(blobs.size(), collectedBlobs.size());
- assertEquals(new HashSet<Blob>(blobs), new
HashSet<Blob>(collectedBlobs));
+ assertEquals(new HashSet<ReferencedBlob>(blobs), new
HashSet<ReferencedBlob>(collectedBlobs));
}
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceTest.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceTest.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BlobReferenceTest.java
Wed Jan 27 08:21:41 2016
@@ -25,6 +25,7 @@ import java.util.Iterator;
import java.util.Random;
import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.plugins.blob.ReferencedBlob;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -42,13 +43,13 @@ public class BlobReferenceTest {
HashSet<String> set = new HashSet<String>();
for (int i = 0; i < 100; i++) {
Blob b = a.createBlob(randomStream(i, 10));
- set.add(b.toString());
+ set.add(new ReferencedBlob(b, "/c" + i).toString());
a.child("c" + i).setProperty("x", b);
}
s.merge(a, EmptyHook.INSTANCE, CommitInfo.EMPTY);
- Iterator<Blob> it = s.getReferencedBlobsIterator();
+ Iterator<ReferencedBlob> it = s.getReferencedBlobsIterator();
while (it.hasNext()) {
- Blob b = it.next();
+ ReferencedBlob b = it.next();
set.remove(b.toString());
}
assertTrue(set.isEmpty());
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoBlobGCTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoBlobGCTest.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoBlobGCTest.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoBlobGCTest.java
Wed Jan 27 08:21:41 2016
@@ -97,6 +97,10 @@ public class MongoBlobGCTest extends Abs
}
}
a.child("c" + i).setProperty("x", b);
+ // Add a duplicated entry
+ if (i == 0) {
+ a.child("cdup").setProperty("x", b);
+ }
}
s.merge(a, EmptyHook.INSTANCE, CommitInfo.EMPTY);
@@ -175,6 +179,7 @@ public class MongoBlobGCTest extends Abs
Set<String> existingAfterGC = gc(0);
assertTrue(Sets.symmetricDifference(state.blobsPresent,
existingAfterGC).isEmpty());
}
+
@Test
public void gcVersionDeleteWithInlined() throws Exception {
DataStoreState state = setUp(false);
@@ -184,6 +189,59 @@ public class MongoBlobGCTest extends Abs
}
@Test
+ public void consistencyCheckInlined() throws Exception {
+ DataStoreState state = setUp(true);
+ addInlined();
+ ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
+ MarkSweepGarbageCollector gcObj = init(86400, executor);
+ long candidates = gcObj.checkConsistency();
+ assertEquals(1, executor.getTaskCount());
+ assertEquals(0, candidates);
+ }
+
+ @Test
+ public void consistencyCheckInit() throws Exception {
+ DataStoreState state = setUp(true);
+ ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
+ MarkSweepGarbageCollector gcObj = init(86400, executor);
+ long candidates = gcObj.checkConsistency();
+ assertEquals(1, executor.getTaskCount());
+ assertEquals(0, candidates);
+ }
+
+ @Test
+ public void consistencyCheckWithGc() throws Exception {
+ DataStoreState state = setUp(true);
+ Set<String> existingAfterGC = gc(0);
+ assertTrue(Sets.symmetricDifference(state.blobsPresent,
existingAfterGC).isEmpty());
+
+ ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
+ MarkSweepGarbageCollector gcObj = init(86400, executor);
+ long candidates = gcObj.checkConsistency();
+ assertEquals(1, executor.getTaskCount());
+ assertEquals(0, candidates);
+ }
+
+ @Test
+ public void consistencyCheckWithRenegadeDelete() throws Exception {
+ DataStoreState state = setUp(true);
+
+ // Simulate faulty state by deleting some blobs directly
+ Random rand = new Random(87);
+ List<String> existing = Lists.newArrayList(state.blobsPresent);
+
+ GarbageCollectableBlobStore store = (GarbageCollectableBlobStore)
+
mk.getNodeStore().getBlobStore();
+ long count =
store.countDeleteChunks(ImmutableList.of(existing.get(rand.nextInt(existing.size()))),
0);
+
+ ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
+ MarkSweepGarbageCollector gcObj = init(86400, executor);
+ long candidates = gcObj.checkConsistency();
+ assertEquals(1, executor.getTaskCount());
+ assertEquals(count, candidates);
+ }
+
+ @Test
public void gcLongRunningBlobCollection() throws Exception {
DataStoreState state = setUp(true);
log.info("{} Blobs added {}", state.blobsAdded.size(),
state.blobsAdded);
@@ -204,12 +262,21 @@ public class MongoBlobGCTest extends Abs
gc.collectGarbage(false);
Set<String> existingAfterGC = iterate();
log.info("{} Blobs existing after gc {}", existingAfterGC.size(),
existingAfterGC);
-
+
assertTrue(Sets.difference(state.blobsPresent,
existingAfterGC).isEmpty());
assertEquals(gc.additionalBlobs,
Sets.symmetricDifference(state.blobsPresent, existingAfterGC));
}
private Set<String> gc(int blobGcMaxAgeInSecs) throws Exception {
+ ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
+ MarkSweepGarbageCollector gc = init(blobGcMaxAgeInSecs, executor);
+ gc.collectGarbage(false);
+
+ assertEquals(0, executor.getTaskCount());
+ return iterate();
+ }
+
+ private MarkSweepGarbageCollector init(int blobGcMaxAgeInSecs,
ThreadPoolExecutor executor) throws Exception {
DocumentNodeStore store = mk.getNodeStore();
String repoId = null;
@@ -219,14 +286,10 @@ public class MongoBlobGCTest extends Abs
new ByteArrayInputStream(new byte[0]),
REPOSITORY.getNameFromId(repoId));
}
- ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
MarkSweepGarbageCollector gc = new MarkSweepGarbageCollector(
new DocumentBlobReferenceRetriever(store),
(GarbageCollectableBlobStore) store.getBlobStore(), executor,
"./target", 5, blobGcMaxAgeInSecs, repoId);
- gc.collectGarbage(false);
-
- assertEquals(0, executor.getTaskCount());
- return iterate();
+ return gc;
}
protected Set<String> iterate() throws Exception {
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/ExternalBlobTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/ExternalBlobTest.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/ExternalBlobTest.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/ExternalBlobTest.java
Wed Jan 27 08:21:41 2016
@@ -108,7 +108,7 @@ public class ExternalBlobTest {
final List<String> refrences = Lists.newArrayList();
store.getTracker().collectBlobReferences(new ReferenceCollector() {
@Override
- public void addReference(String reference) {
+ public void addReference(String reference, String nodeId) {
assertNotNull(reference);
refrences.add(reference);
}
Modified:
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentDataStoreBlobGCTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentDataStoreBlobGCTest.java?rev=1726952&r1=1726951&r2=1726952&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentDataStoreBlobGCTest.java
(original)
+++
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentDataStoreBlobGCTest.java
Wed Jan 27 08:21:41 2016
@@ -22,7 +22,6 @@ import static org.apache.commons.io.File
import static
org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils.SharedStoreRecordType.REPOSITORY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -203,29 +202,47 @@ public class SegmentDataStoreBlobGCTest
Set<String> existingAfterGC = gcInternal(86400);
assertTrue(Sets.symmetricDifference(state.blobsAdded,
existingAfterGC).isEmpty());
}
-
- private Set<String> gcInternal(long maxBlobGcInSecs) throws Exception {
- String repoId = null;
- if (SharedDataStoreUtils.isShared(store.getBlobStore())) {
- repoId = ClusterRepositoryInfo.createId(nodeStore);
- ((SharedDataStore) store.getBlobStore()).addMetadataRecord(
- new ByteArrayInputStream(new byte[0]),
- REPOSITORY.getNameFromId(repoId));
- }
-
+
+ @Test
+ public void consistencyCheckInit() throws Exception {
+ DataStoreState state = setUp();
ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
- MarkSweepGarbageCollector gc = new MarkSweepGarbageCollector(
- new SegmentBlobReferenceRetriever(store.getTracker()),
- (GarbageCollectableBlobStore) store.getBlobStore(),
executor, "./target", 2048, maxBlobGcInSecs,
-
repoId);
- gc.collectGarbage(false);
-
- assertEquals(0, executor.getTaskCount());
- Set<String> existingAfterGC = iterate();
- log.info("{} blobs existing after gc : {}", existingAfterGC.size(),
existingAfterGC);
- return existingAfterGC;
+ MarkSweepGarbageCollector gcObj = init(86400, executor);
+ long candidates = gcObj.checkConsistency();
+ assertEquals(1, executor.getTaskCount());
+ assertEquals(0, candidates);
}
-
+
+ @Test
+ public void consistencyCheckWithGc() throws Exception {
+ DataStoreState state = setUp();
+ Set<String> existingAfterGC = gcInternal(0);
+ assertTrue(Sets.symmetricDifference(state.blobsPresent,
existingAfterGC).isEmpty());
+
+ ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
+ MarkSweepGarbageCollector gcObj = init(86400, executor);
+ long candidates = gcObj.checkConsistency();
+ assertEquals(1, executor.getTaskCount());
+ assertEquals(0, candidates);
+ }
+
+ @Test
+ public void consistencyCheckWithRenegadeDelete() throws Exception {
+ DataStoreState state = setUp();
+
+ // Simulate faulty state by deleting some blobs directly
+ Random rand = new Random(87);
+ List<String> existing = Lists.newArrayList(state.blobsPresent);
+
+ long count =
blobStore.countDeleteChunks(ImmutableList.of(existing.get(rand.nextInt(existing.size()))),
0);
+
+ ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
+ MarkSweepGarbageCollector gcObj = init(86400, executor);
+ long candidates = gcObj.checkConsistency();
+ assertEquals(1, executor.getTaskCount());
+ assertEquals(count, candidates);
+ }
+
@Test
public void gcLongRunningBlobCollection() throws Exception {
DataStoreState state = setUp();
@@ -250,7 +267,33 @@ public class SegmentDataStoreBlobGCTest
assertTrue(Sets.difference(state.blobsPresent,
existingAfterGC).isEmpty());
assertEquals(gc.additionalBlobs,
Sets.symmetricDifference(state.blobsPresent, existingAfterGC));
}
-
+
+ private Set<String> gcInternal(long maxBlobGcInSecs) throws Exception {
+ ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
+ MarkSweepGarbageCollector gc = init(maxBlobGcInSecs, executor);
+ gc.collectGarbage(false);
+
+ assertEquals(0, executor.getTaskCount());
+ Set<String> existingAfterGC = iterate();
+ log.info("{} blobs existing after gc : {}", existingAfterGC.size(),
existingAfterGC);
+ return existingAfterGC;
+ }
+
+ private MarkSweepGarbageCollector init(long blobGcMaxAgeInSecs,
ThreadPoolExecutor executor) throws Exception {
+ String repoId = null;
+ if (SharedDataStoreUtils.isShared(store.getBlobStore())) {
+ repoId = ClusterRepositoryInfo.createId(nodeStore);
+ ((SharedDataStore) store.getBlobStore()).addMetadataRecord(
+ new ByteArrayInputStream(new byte[0]),
+ REPOSITORY.getNameFromId(repoId));
+ }
+ MarkSweepGarbageCollector gc = new MarkSweepGarbageCollector(
+ new SegmentBlobReferenceRetriever(store.getTracker()),
+ (GarbageCollectableBlobStore) store.getBlobStore(), executor,
"./target", 2048, blobGcMaxAgeInSecs,
+ repoId);
+ return gc;
+ }
+
protected Set<String> iterate() throws Exception {
Iterator<String> cur = blobStore.getAllChunkIds(0);