diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml index 17477c71b0..be3ab964b8 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/avm-common-SqlMap.xml @@ -784,6 +784,43 @@ order by version_id + + + + + + + + update diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml index 900d492fe5..21390c983b 100644 --- a/config/alfresco/public-services-context.xml +++ b/config/alfresco/public-services-context.xml @@ -912,6 +912,9 @@ hasAspect getAPath getGuid + getStoreVersionsFrom + getStoreVersionsTo + getStoreVersionsBetween diff --git a/source/java/org/alfresco/repo/avm/AVMLockingAwareService.java b/source/java/org/alfresco/repo/avm/AVMLockingAwareService.java index c298fb30b8..bb50096024 100644 --- a/source/java/org/alfresco/repo/avm/AVMLockingAwareService.java +++ b/source/java/org/alfresco/repo/avm/AVMLockingAwareService.java @@ -949,4 +949,20 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa grabLock(AVMUtil.extendAVMPath(path, name)); fService.createFile(path, name, in, aspects, properties); } + + public List getStoreVersionsTo(String name, int version) + { + return fService.getStoreVersionsTo(name, version); + } + + public List getStoreVersionsFrom(String name, int version) + { + return fService.getStoreVersionsFrom(name, version); + } + + public List getStoreVersionsBetween(String name, int from, int to) + { + return fService.getStoreVersionsBetween(name, from, to); + } + } diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java index 790d94375d..08b63d58a1 100644 --- a/source/java/org/alfresco/repo/avm/AVMRepository.java +++ b/source/java/org/alfresco/repo/avm/AVMRepository.java @@ -3428,4 +3428,50 @@ public class AVMRepository } return store.getStoreAcl(); } + + /** + * @param name + * @param version + * @return + */ + public List getAVMStoreVersionsTo(String name, int version) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getVersionsTo(version); + } + + /** + * @param name + * @param version + * @return + */ + public List getAVMStoreVersionsFrom(String name, int version) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getVersionsFrom(version); + } + + /** + * @param name + * @param startVersion + * @param endVersion + * @return + */ + public List getAVMStoreVersionsBetween(String name, int startVersion, int endVersion) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getVersionsBetween(startVersion, endVersion); + } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java index 699a8a0805..7dd0a3878c 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java @@ -1617,4 +1617,38 @@ public class AVMServiceImpl implements AVMService } fAVMRepository.setMimeType(path, mimeType); } + + public List getStoreVersionsTo(String name, int version) + { + if (name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getAVMStoreVersionsTo(name, version); + } + + public List getStoreVersionsFrom(String name, int version) + { + if (name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getAVMStoreVersionsFrom(name, version); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.avm.AVMService#getStoreVersionsBetween(java.lang.String, int, int) + */ + public List getStoreVersionsBetween(String name, int startVersion, int endVersion) + { + if (name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getAVMStoreVersionsBetween(name, startVersion, endVersion); + } + + + + } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index 77a8972690..5a49ecba5d 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -29,11 +29,15 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.SortedMap; import java.util.TreeMap; +import javax.transaction.UserTransaction; + import org.alfresco.config.JNDIConstants; import org.alfresco.model.ContentModel; import org.alfresco.model.WCMModel; @@ -47,6 +51,8 @@ import org.alfresco.repo.avm.actions.SimpleAVMSubmitAction; import org.alfresco.repo.avm.util.BulkLoader; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.domain.hibernate.SessionSizeResourceManager; +import org.alfresco.repo.search.impl.lucene.ADMLuceneSearcherImpl; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -65,6 +71,7 @@ import org.alfresco.service.cmr.avmsync.AVMDifference; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.remote.RepoRemote; +import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.CrossRepositoryCopyService; @@ -95,6 +102,430 @@ public class AVMServiceTest extends AVMServiceTestBase super.testSetup(); } + public void test_ALF_786() throws Exception + { + int threads= 4; + int loops = 10; + int snapshotsPerLoop = 4; + + + int startVersion; + UserTransaction testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + fService.createDirectory("main:/", "test"); + startVersion = fService.createSnapshot("main", null, null).get("main"); + + testTX.commit(); + testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + + + StoreRef storeRef = AVMNodeConverter.ToStoreRef("main"); + SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true); + ResultSet results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\""); + assertEquals(0, results.length()); + results.close(); + testTX.commit(); + + Thread runner = null; + + for (int i = 0; i < threads; i++) + { + runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.CREATE, loops); + } + if (runner != null) + { + runner.start(); + + try + { + runner.join(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + // snap + testTX.commit(); + testTX = fTransactionService.getUserTransaction(); + testTX.begin();; + SortedMap listing = fService.getDirectoryListing(-1, "main:/test"); + assertEquals(loops, listing.size()); + for(AVMNodeDescriptor node : listing.values()) + { + System.out.println("Listed: "+node.getPath()+" "+node.getVersionID()); + } + List diffs = fSyncService.compare(startVersion, "main:/", -1, "main:/", null); + assertEquals(loops, diffs.size()); + for(AVMDifference diff : diffs) + { + AVMNodeDescriptor desc = fService.lookup(diff.getDestinationVersion(), diff.getDestinationPath(), true); + assertFalse(desc.isDeleted()); + } + + + + searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true); + results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\""); + for(ResultSetRow row : results) + { + System.out.println("Found: "+row.getNodeRef()); + } + assertEquals(loops, results.length()); + results.close(); + testTX.commit(); + + // update + + runner = null; + for (int i = 0; i < threads; i++) + { + runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.UPDATE, loops); + } + if (runner != null) + { + runner.start(); + + try + { + runner.join(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true); + results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\""); + for(ResultSetRow row : results) + { + System.out.println("Found: "+row.getNodeRef()); + } + assertEquals(loops, results.length()); + results.close(); + testTX.commit(); + + // delete + + runner = null; + for (int i = 0; i < threads; i++) + { + runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.DELETE, loops); + } + if (runner != null) + { + runner.start(); + + try + { + runner.join(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true); + results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\""); + for(ResultSetRow row : results) + { + System.out.println("Found: "+row.getNodeRef()); + } + assertEquals(0, results.length()); + results.close(); + testTX.commit(); + + // recreate + + runner = null; + for (int i = 0; i < threads; i++) + { + runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.CREATE, loops); + } + if (runner != null) + { + runner.start(); + + try + { + runner.join(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true); + results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\""); + for(ResultSetRow row : results) + { + System.out.println("Found: "+row.getNodeRef()); + } + assertEquals(loops, results.length()); + results.close(); + testTX.commit(); + + //move + + runner = null; + for (int i = 0; i < threads; i++) + { + runner = new Nester("Concurrent-" + i, runner, false, snapshotsPerLoop, Nester.Mode.MOVE, loops); + } + if (runner != null) + { + runner.start(); + + try + { + runner.join(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true); + results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\""); + for(ResultSetRow row : results) + { + System.out.println("Found: "+row.getNodeRef()); + } + assertEquals(loops, results.length()); + results.close(); + testTX.commit(); + } + + public void xtest_ALF_786_PLUS() throws Exception + { + int startVersion; + UserTransaction testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + fService.createDirectory("main:/", "test"); + startVersion = fService.createSnapshot("main", null, null).get("main"); + + testTX.commit(); + testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + + + StoreRef storeRef = AVMNodeConverter.ToStoreRef("main"); + SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true); + ResultSet results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\""); + assertEquals(0, results.length()); + results.close(); + testTX.commit(); + + Thread runner = null; + + for (int i = 0; i < 10; i++) + { + runner = new Nester("Concurrent-" + i, runner, true, 10, Nester.Mode.CREATE, 10 ); + } + if (runner != null) + { + runner.start(); + + try + { + runner.join(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + testTX = fTransactionService.getUserTransaction(); + testTX.begin(); + // snap + testTX.commit(); + testTX = fTransactionService.getUserTransaction(); + testTX.begin();; + SortedMap listing = fService.getDirectoryListing(-1, "main:/test"); + assertEquals(100, listing.size()); + for(AVMNodeDescriptor node : listing.values()) + { + System.out.println("Listed: "+node.getPath()+" "+node.getVersionID()); + } + List diffs = fSyncService.compare(startVersion, "main:/", -1, "main:/", null); + assertEquals(100, diffs.size()); + for(AVMDifference diff : diffs) + { + AVMNodeDescriptor desc = fService.lookup(diff.getDestinationVersion(), diff.getDestinationPath(), true); + assertFalse(desc.isDeleted()); + } + + + + searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef("main"), true); + results = searchService.query(storeRef, "lucene", "PATH:\"/test/*\""); + for(ResultSetRow row : results) + { + System.out.println("Found: "+row.getNodeRef()); + } + assertEquals(100, results.length()); + results.close(); + testTX.commit(); + } + + static class Nester extends Thread + { + enum Mode {CREATE, UPDATE, DELETE, MOVE}; + + Thread waiter; + + int i; + + boolean multiThread; + + int snapshotCount; + + Mode mode; + + int loopCount; + + Nester(String name, Thread waiter, boolean multiThread, int snapshotCount, Mode mode, int loopCount) + { + super(name); + this.setDaemon(true); + this.waiter = waiter; + this.multiThread = multiThread; + this.snapshotCount = snapshotCount; + this.mode = mode; + this.loopCount = loopCount; + } + + public void run() + { + fAuthenticationComponent.setSystemUserAsCurrentUser(); + if (waiter != null) + { + waiter.start(); + } + try + { + System.out.println("Start " + this.getName()); + for(i = 0; i < loopCount; i++) + { + RetryingTransactionCallback create = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + fService.createFile("main:/test", getName()+"-"+i); + + return null; + } + }; + RetryingTransactionCallback update = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + fService.setMimeType("main:/test/"+getName()+"-"+i, "text/plain"); + + return null; + } + }; + RetryingTransactionCallback delete = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + fService.removeNode("main:/test/"+getName()+"-"+i); + + return null; + } + }; + RetryingTransactionCallback move = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + fService.rename("main:/test/", getName()+"-"+i, "main:/test/", "MOVED-"+getName()+"-"+i); + + return null; + } + }; + if(multiThread || (waiter == null)) + { + // only one thread creates for 786 + switch(mode) + { + case CREATE: + fRetryingTransactionHelper.doInTransaction(create); + System.out.println(getName()+i); + break; + case UPDATE: + fRetryingTransactionHelper.doInTransaction(update); + break; + case DELETE: + fRetryingTransactionHelper.doInTransaction(delete); + break; + case MOVE: + fRetryingTransactionHelper.doInTransaction(move); + break; + default: + } + + } + + RetryingTransactionCallback snap = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + fService.createSnapshot("main", null, null); + + + return null; + } + }; + for(int s = 0; s < snapshotCount; s++) + { + fRetryingTransactionHelper.doInTransaction(snap); + } + } + System.out.println("End " + this.getName()); + } + catch (Exception e) + { + System.out.println("End " + this.getName() + " with error " + e.getMessage()); + e.printStackTrace(); + } + finally + { + fAuthenticationComponent.clearCurrentSecurityContext(); + } + if (waiter != null) + { + try + { + waiter.join(); + System.out.println("Waited for " + waiter.getName()+" by "+this.getName()); + } + catch (InterruptedException e) + { + } + } + } + + } + + + public void testDiffOrder() { try @@ -348,6 +779,57 @@ public class AVMServiceTest extends AVMServiceTestBase assertEquals(1, fService.getStoreVersions("main", null, new Date(times.get(0))).size()); assertEquals(3, fService.getStoreVersions("main", new Date(times.get(0)), null).size()); assertEquals(2, fService.getStoreVersions("main", new Date(times.get(1)), new Date(System.currentTimeMillis())).size()); + + // TO + assertEquals(1, fService.getStoreVersionsTo("main", 0).size()); + assertEquals(0, fService.getStoreVersionsTo("main", 0).get(0).getVersionID()); + assertEquals(2, fService.getStoreVersionsTo("main", 1).size()); + assertEquals(0, fService.getStoreVersionsTo("main", 1).get(0).getVersionID()); + assertEquals(1, fService.getStoreVersionsTo("main", 1).get(1).getVersionID()); + assertEquals(3, fService.getStoreVersionsTo("main", 2).size()); + assertEquals(0, fService.getStoreVersionsTo("main", 2).get(0).getVersionID()); + assertEquals(1, fService.getStoreVersionsTo("main", 2).get(1).getVersionID()); + assertEquals(2, fService.getStoreVersionsTo("main", 2).get(2).getVersionID()); + assertEquals(4, fService.getStoreVersionsTo("main", 3).size()); + assertEquals(0, fService.getStoreVersionsTo("main", 3).get(0).getVersionID()); + assertEquals(1, fService.getStoreVersionsTo("main", 3).get(1).getVersionID()); + assertEquals(2, fService.getStoreVersionsTo("main", 3).get(2).getVersionID()); + assertEquals(3, fService.getStoreVersionsTo("main", 3).get(3).getVersionID()); + + // FROM + + assertEquals(4, fService.getStoreVersionsFrom("main", 0).size()); + assertEquals(0, fService.getStoreVersionsFrom("main", 0).get(0).getVersionID()); + assertEquals(1, fService.getStoreVersionsFrom("main", 0).get(1).getVersionID()); + assertEquals(2, fService.getStoreVersionsFrom("main", 0).get(2).getVersionID()); + assertEquals(3, fService.getStoreVersionsFrom("main", 0).get(3).getVersionID()); + assertEquals(3, fService.getStoreVersionsFrom("main", 1).size()); + assertEquals(1, fService.getStoreVersionsFrom("main", 1).get(0).getVersionID()); + assertEquals(2, fService.getStoreVersionsFrom("main", 1).get(1).getVersionID()); + assertEquals(3, fService.getStoreVersionsFrom("main", 1).get(2).getVersionID()); + assertEquals(2, fService.getStoreVersionsFrom("main", 2).size()); + assertEquals(2, fService.getStoreVersionsFrom("main", 2).get(0).getVersionID()); + assertEquals(3, fService.getStoreVersionsFrom("main", 2).get(1).getVersionID()); + assertEquals(1, fService.getStoreVersionsFrom("main", 3).size()); + assertEquals(3, fService.getStoreVersionsFrom("main", 3).get(0).getVersionID()); + assertEquals(0, fService.getStoreVersionsFrom("main", 4).size()); + + // BETWEEN + + assertEquals(1, fService.getStoreVersionsBetween("main", 0, 0).size()); + assertEquals(0, fService.getStoreVersionsBetween("main", 0, 0).get(0).getVersionID()); + assertEquals(1, fService.getStoreVersionsBetween("main", 1, 1).size()); + assertEquals(1, fService.getStoreVersionsBetween("main", 1, 1).get(0).getVersionID()); + assertEquals(1, fService.getStoreVersionsBetween("main", 2, 2).size()); + assertEquals(2, fService.getStoreVersionsBetween("main", 2, 2).get(0).getVersionID()); + assertEquals(1, fService.getStoreVersionsBetween("main", 3, 3).size()); + assertEquals(3, fService.getStoreVersionsBetween("main", 3, 3).get(0).getVersionID()); + assertEquals(0, fService.getStoreVersionsBetween("main", 4, 4).size()); + + + assertEquals(2, fService.getStoreVersionsBetween("main", 1, 2).size()); + assertEquals(1, fService.getStoreVersionsBetween("main", 1, 2).get(0).getVersionID()); + assertEquals(2, fService.getStoreVersionsBetween("main", 1, 2).get(1).getVersionID()); } catch (Exception e) { @@ -2182,7 +2664,7 @@ public class AVMServiceTest extends AVMServiceTestBase { setupBasicTree(); fService.removeNode("main:/a/b/c/foo/"); - fService.removeNode("main://d"); + fService.removeNode("main:/d"); fService.createSnapshot("main", null, null); StoreRef storeRef = AVMNodeConverter.ToStoreRef("main"); @@ -2208,7 +2690,7 @@ public class AVMServiceTest extends AVMServiceTestBase // TODO: Fix auth in AVMDiskDriver and more?? results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@" + ContentModel.PROP_CREATOR) + ":admin"); - if (results.length() == 6) + if (results.length() == 7) { for (ResultSetRow row : results) { diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java index b5ff8c84da..6f54b26d95 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java @@ -29,7 +29,9 @@ import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; import org.alfresco.repo.search.IndexerAndSearcher; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; +import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.locking.AVMLockingService; @@ -74,6 +76,10 @@ public class AVMServiceTestBase extends TestCase */ private long fStartTime; + protected static RetryingTransactionHelper fRetryingTransactionHelper; + + protected static AuthenticationComponent fAuthenticationComponent; + protected static AVMSnapShotTriggeredIndexingMethodInterceptor fIndexingInterceptor; protected static TransactionService fTransactionService; @@ -108,6 +114,8 @@ public class AVMServiceTestBase extends TestCase fLockingService = (AVMLockingService)fContext.getBean("AVMLockingService"); fIndexingInterceptor = (AVMSnapShotTriggeredIndexingMethodInterceptor)fContext.getBean("avmSnapShotTriggeredIndexingMethodInterceptor"); fAuthService = (AuthenticationService)fContext.getBean("AuthenticationService"); + fAuthenticationComponent = (AuthenticationComponent) fContext.getBean("authenticationComponent"); + fRetryingTransactionHelper = (RetryingTransactionHelper) fContext.getBean("retryingTransactionHelper"); CreateStoreTxnListener cstl = (CreateStoreTxnListener)fContext.getBean("createStoreTxnListener"); cstl.addCallback( diff --git a/source/java/org/alfresco/repo/avm/AVMStore.java b/source/java/org/alfresco/repo/avm/AVMStore.java index 2c67e00616..82e00c1095 100644 --- a/source/java/org/alfresco/repo/avm/AVMStore.java +++ b/source/java/org/alfresco/repo/avm/AVMStore.java @@ -211,6 +211,28 @@ public interface AVMStore */ public List getVersions(); + /** + * Get all the versions starting from the last until the version specified + * @param version - the version which which to end + * @return - the versions in descending order + */ + public List getVersionsFrom(int version); + + /** + * Get all the versions after and including the one specified + * @param version - the version to start from + * @return - the versions in ascending order + */ + public List getVersionsTo(int version); + + /** + * Get all versions from an including startVersion up to but NOT including endVersion + * @param startVersion + * @param endVersion + * @return - the versions in ascending order + */ + public List getVersionsBetween(int startVersion, int endVersion); + /** * Get the versions from between the given dates. From or to * may be null but not both. diff --git a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java index abd0b68e0e..1171e8c7fb 100644 --- a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java @@ -951,6 +951,65 @@ public class AVMStoreImpl implements AVMStore return descs; } + + + public List getVersionsTo(int version) + { + List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsTo(this, version); + List descs = new ArrayList(); + for (VersionRoot vr : versions) + { + VersionDescriptor desc = + new VersionDescriptor(getName(), + vr.getVersionID(), + vr.getCreator(), + vr.getCreateDate(), + vr.getTag(), + vr.getDescription()); + descs.add(desc); + } + return descs; + } + + public List getVersionsFrom(int version) + { + List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsFrom(this, version); + List descs = new ArrayList(); + for (VersionRoot vr : versions) + { + VersionDescriptor desc = + new VersionDescriptor(getName(), + vr.getVersionID(), + vr.getCreator(), + vr.getCreateDate(), + vr.getTag(), + vr.getDescription()); + descs.add(desc); + } + return descs; + } + + + + + public List getVersionsBetween(int startVersion, int endVersion) + { + List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsBetween(this, startVersion, endVersion); + List descs = new ArrayList(); + for (VersionRoot vr : versions) + { + VersionDescriptor desc = + new VersionDescriptor(getName(), + vr.getVersionID(), + vr.getCreator(), + vr.getCreateDate(), + vr.getTag(), + vr.getDescription()); + descs.add(desc); + } + return descs; + } + /** * Get the AVMRepository. * @return The AVMRepository diff --git a/source/java/org/alfresco/repo/avm/MultiTAVMService.java b/source/java/org/alfresco/repo/avm/MultiTAVMService.java index b8937b63fa..d5c69f501d 100644 --- a/source/java/org/alfresco/repo/avm/MultiTAVMService.java +++ b/source/java/org/alfresco/repo/avm/MultiTAVMService.java @@ -823,6 +823,24 @@ public class MultiTAVMService implements AVMService } + public List getStoreVersionsTo(String name, int version) + { + // TODO - review + return fService.getStoreVersionsTo(name, version); + } + + public List getStoreVersionsFrom(String name, int version) + { + // TODO - review + return fService.getStoreVersionsFrom(name, version); + } + + public List getStoreVersionsBetween(String name, int from, int to) + { + // TODO - review + return fService.getStoreVersionsBetween(name, from, to); + } + private String getTenantStoreName(String avmStoreName) { if ((avmStoreName == null) || (! isTenantServiceEnabled())) diff --git a/source/java/org/alfresco/repo/avm/VersionRootDAO.java b/source/java/org/alfresco/repo/avm/VersionRootDAO.java index 47f9414a63..c30a036be4 100644 --- a/source/java/org/alfresco/repo/avm/VersionRootDAO.java +++ b/source/java/org/alfresco/repo/avm/VersionRootDAO.java @@ -85,4 +85,26 @@ public interface VersionRootDAO * @return The highest numbered id. */ public Integer getMaxVersionID(AVMStore store); + + /** + * @param store + * @param version + * @return + */ + public List getByVersionsTo(AVMStore store, int version); + + /** + * @param store + * @param version + * @return + */ + public List getByVersionsFrom(AVMStore store, int version); + + /** + * @param store + * @param startVersion + * @param endVersion + * @return + */ + public List getByVersionsBetween(AVMStore store, int startVersion, int endVersion); } diff --git a/source/java/org/alfresco/repo/avm/ibatis/VersionRootDAOIbatis.java b/source/java/org/alfresco/repo/avm/ibatis/VersionRootDAOIbatis.java index b5636e2abc..482ba3b6ba 100644 --- a/source/java/org/alfresco/repo/avm/ibatis/VersionRootDAOIbatis.java +++ b/source/java/org/alfresco/repo/avm/ibatis/VersionRootDAOIbatis.java @@ -25,6 +25,7 @@ import java.util.List; import org.alfresco.repo.avm.AVMDAOs; import org.alfresco.repo.avm.AVMNode; import org.alfresco.repo.avm.AVMStore; +import org.alfresco.repo.avm.AVMStoreImpl; import org.alfresco.repo.avm.DirectoryNode; import org.alfresco.repo.avm.VersionRoot; import org.alfresco.repo.avm.VersionRootDAO; @@ -140,6 +141,43 @@ class VersionRootDAOIbatis implements VersionRootDAO return new Integer(maxVersionId.intValue()); } + + + public List getByVersionsTo(AVMStore store, int version) + { + List vrEntities = AVMDAOs.Instance().newAVMVersionRootDAO.getByVersionsTo(store.getId(), version); + List vrs = new ArrayList(vrEntities.size()); + for (AVMVersionRootEntity vrEntity : vrEntities) + { + vrs.add(convertVersionRootEntityToVersionRoot(vrEntity)); + } + return vrs; + } + + public List getByVersionsFrom(AVMStore store, int version) + { + List vrEntities = AVMDAOs.Instance().newAVMVersionRootDAO.getByVersionsFrom(store.getId(), version); + List vrs = new ArrayList(vrEntities.size()); + for (AVMVersionRootEntity vrEntity : vrEntities) + { + vrs.add(convertVersionRootEntityToVersionRoot(vrEntity)); + } + return vrs; + } + + + + public List getByVersionsBetween(AVMStore store, int startVersion, int endVersion) + { + List vrEntities = AVMDAOs.Instance().newAVMVersionRootDAO.getByVersionsBetween(store.getId(), startVersion, endVersion); + List vrs = new ArrayList(vrEntities.size()); + for (AVMVersionRootEntity vrEntity : vrEntities) + { + vrs.add(convertVersionRootEntityToVersionRoot(vrEntity)); + } + return vrs; + } + private AVMVersionRootEntity convertVersionRootToVersionRootEntity(VersionRoot vr) { if (vr == null) diff --git a/source/java/org/alfresco/repo/domain/avm/AVMVersionRootDAO.java b/source/java/org/alfresco/repo/domain/avm/AVMVersionRootDAO.java index 9eb8fb4dd4..9a103cde61 100644 --- a/source/java/org/alfresco/repo/domain/avm/AVMVersionRootDAO.java +++ b/source/java/org/alfresco/repo/domain/avm/AVMVersionRootDAO.java @@ -103,4 +103,26 @@ public interface AVMVersionRootDAO public void deleteVersionLayeredNodeEntries(long versionRootId); public List getVersionLayeredNodeEntries(long versionRootId); + + /** + * @param id + * @param version + * @return + */ + public List getByVersionsTo(long id, int version); + + /** + * @param id + * @param version + * @return + */ + public List getByVersionsFrom(long id, int version); + + /** + * @param id + * @param startVersion + * @param endVersion + * @return + */ + public List getByVersionsBetween(long id, int startVersion, int endVersion); } diff --git a/source/java/org/alfresco/repo/domain/avm/AbstractAVMVersionRootDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/AbstractAVMVersionRootDAOImpl.java index c949b93932..b39da86d2b 100644 --- a/source/java/org/alfresco/repo/domain/avm/AbstractAVMVersionRootDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/avm/AbstractAVMVersionRootDAOImpl.java @@ -283,4 +283,27 @@ public abstract class AbstractAVMVersionRootDAOImpl implements AVMVersionRootDAO protected abstract AVMVersionLayeredNodeEntryEntity createVersionLayeredNodeEntryEntity(long versionRootId, String md5sum, String path); protected abstract int deleteVersionLayeredNodeEntryEntities(long versionRootId); protected abstract List getVersionLayeredNodeEntryEntities(long storeId); + + + protected abstract List getVersionRootEntitiesByVersionsTo(long storeId, long to); + protected abstract List getVersionRootEntitiesByVersionsFrom(long storeId, long from); + protected abstract List getVersionRootEntitiesByVersionsBetween(long storeId, long from, long to); + + public List getByVersionsTo(long id, int version) + { + return getVersionRootEntitiesByVersionsTo(id, version); + } + + public List getByVersionsFrom(long id, int version) + { + return getVersionRootEntitiesByVersionsFrom(id, version); + } + + public List getByVersionsBetween(long id, int startVersion, int endVersion) + { + return getVersionRootEntitiesByVersionsBetween(id, startVersion, endVersion); + } + + + } diff --git a/source/java/org/alfresco/repo/domain/avm/ibatis/AVMVersionRootDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/ibatis/AVMVersionRootDAOImpl.java index c484d70e4e..1a0fab5ae7 100644 --- a/source/java/org/alfresco/repo/domain/avm/ibatis/AVMVersionRootDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/avm/ibatis/AVMVersionRootDAOImpl.java @@ -46,9 +46,13 @@ public class AVMVersionRootDAOImpl extends AbstractAVMVersionRootDAOImpl private static final String SELECT_AVM_VERSION_ROOT_BY_STORE_VERSION ="alfresco.avm.select_AVMVersionRootByStoreVersion"; private static final String SELECT_AVM_VERSION_ROOT_BY_ROOT_NODE_ID ="alfresco.avm.select_AVMVersionRootByRootNodeId"; private static final String SELECT_AVM_VERSION_ROOTS_BY_STORE_ID ="alfresco.avm.select_AVMVersionRootsByStoreId"; - private static final String SELECT_AVM_VERSION_ROOTS_BY_TO ="alfresco.avm.select_AVMVersionRootsByTo"; - private static final String SELECT_AVM_VERSION_ROOTS_BY_FROM ="alfresco.avm.select_AVMVersionRootsByFrom"; - private static final String SELECT_AVM_VERSION_ROOTS_BETWEEN ="alfresco.avm.select_AVMVersionRootsBetween"; + private static final String SELECT_AVM_VERSION_ROOTS_BY_DATE_TO ="alfresco.avm.select_AVMVersionRootsByTo"; + private static final String SELECT_AVM_VERSION_ROOTS_BY_DATE_FROM ="alfresco.avm.select_AVMVersionRootsByFrom"; + private static final String SELECT_AVM_VERSION_ROOTS_BY_DATES_BETWEEN ="alfresco.avm.select_AVMVersionRootsBetween"; + + private static final String SELECT_AVM_VERSION_ROOTS_BY_VERSION_TO ="alfresco.avm.select_AVMVersionRootsByVersionTo"; + private static final String SELECT_AVM_VERSION_ROOTS_BY_VERSION_FROM ="alfresco.avm.select_AVMVersionRootsByVersionFrom"; + private static final String SELECT_AVM_VERSION_ROOTS_BY_VERSIONS_BETWEEN ="alfresco.avm.select_AVMVersionRootsByVersionsBetween"; private static final String INSERT_AVM_VERSION_LAYERED_NODE_ENTRY ="alfresco.avm.insert_AVMVersionLayeredNodeEntry"; private static final String DELETE_AVM_VERSION_LAYERED_NODE_ENTRIES ="alfresco.avm.delete_AVMVersionLayeredNodeEntries"; @@ -138,7 +142,7 @@ public class AVMVersionRootDAOImpl extends AbstractAVMVersionRootDAOImpl Map params = new HashMap(2); params.put("id", storeId); params.put("to", to); - return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BY_TO, params); + return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BY_DATE_TO, params); } @SuppressWarnings("unchecked") @@ -147,7 +151,7 @@ public class AVMVersionRootDAOImpl extends AbstractAVMVersionRootDAOImpl Map params = new HashMap(2); params.put("id", storeId); params.put("from", from); - return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BY_FROM, params); + return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BY_DATE_FROM, params); } @SuppressWarnings("unchecked") @@ -157,9 +161,37 @@ public class AVMVersionRootDAOImpl extends AbstractAVMVersionRootDAOImpl params.put("id", storeId); params.put("from", from); params.put("to", to); - return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BETWEEN, params); + return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BY_DATES_BETWEEN, params); } + @Override + protected List getVersionRootEntitiesByVersionsBetween(long storeId, long from, long to) + { + Map params = new HashMap(3); + params.put("id", storeId); + params.put("from", from); + params.put("to", to); + return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BY_VERSIONS_BETWEEN, params); + } + + @Override + protected List getVersionRootEntitiesByVersionsFrom(long storeId, long from) + { + Map params = new HashMap(2); + params.put("id", storeId); + params.put("from", from); + return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BY_VERSION_FROM, params); + } + + @Override + protected List getVersionRootEntitiesByVersionsTo(long storeId, long to) + { + Map params = new HashMap(2); + params.put("id", storeId); + params.put("to", to); + return (List) template.queryForList(SELECT_AVM_VERSION_ROOTS_BY_VERSION_TO, params); + } + @Override protected int deleteVersionRootEntity(long vrEntityId) { diff --git a/source/java/org/alfresco/repo/search/AVMSnapShotTriggeredIndexingMethodInterceptor.java b/source/java/org/alfresco/repo/search/AVMSnapShotTriggeredIndexingMethodInterceptor.java index 8753bc85f1..6dedaa63c5 100644 --- a/source/java/org/alfresco/repo/search/AVMSnapShotTriggeredIndexingMethodInterceptor.java +++ b/source/java/org/alfresco/repo/search/AVMSnapShotTriggeredIndexingMethodInterceptor.java @@ -36,7 +36,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** - * Method interceptor for atomic indexing of AVM entries The properties can defined how stores are indexed based on type + * Method interceptor for atomic indexing of AVM entries The properties can defined how stores are indexed based on type * (as set by Alfresco the Web site management UI) or based on the name of the store. Creates and deletes are indexed * synchronously. Updates may be asynchronous, synchronous or ignored by the index. * @@ -100,14 +100,14 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte { String store = (String) mi.getArguments()[0]; Object returnValue = mi.proceed(); - - if (getIndexMode(store) != IndexMode.UNINDEXED) + + if (getIndexMode(store) != IndexMode.UNINDEXED) { - AVMLuceneIndexer avmIndexer = getIndexer(store); - if (avmIndexer != null) - { - avmIndexer.deleteIndex(store, IndexMode.SYNCHRONOUS); - } + AVMLuceneIndexer avmIndexer = getIndexer(store); + if (avmIndexer != null) + { + avmIndexer.deleteIndex(store, IndexMode.SYNCHRONOUS); + } } return returnValue; } @@ -115,10 +115,10 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte { String store = (String) mi.getArguments()[0]; Object returnValue = mi.proceed(); - if (getIndexMode(store) != IndexMode.UNINDEXED) - { - createIndex(store); - } + if (getIndexMode(store) != IndexMode.UNINDEXED) + { + createIndex(store); + } return returnValue; } else if (mi.getMethod().getName().equals("renameStore")) @@ -127,24 +127,24 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte String to = (String) mi.getArguments()[1]; Object returnValue = mi.proceed(); int after = avmService.getLatestSnapshotID(to); - - if (getIndexMode(from) != IndexMode.UNINDEXED) + + if (getIndexMode(from) != IndexMode.UNINDEXED) { - AVMLuceneIndexer avmIndexer = getIndexer(from); - if (avmIndexer != null) - { - avmIndexer.deleteIndex(from, IndexMode.SYNCHRONOUS); - } + AVMLuceneIndexer avmIndexer = getIndexer(from); + if (avmIndexer != null) + { + avmIndexer.deleteIndex(from, IndexMode.SYNCHRONOUS); + } } - - if (getIndexMode(to) != IndexMode.UNINDEXED) + + if (getIndexMode(to) != IndexMode.UNINDEXED) { - AVMLuceneIndexer avmIndexer = getIndexer(to); - if (avmIndexer != null) - { - avmIndexer.createIndex(to, IndexMode.SYNCHRONOUS); - avmIndexer.index(to, 0, after, getIndexMode(to)); - } + AVMLuceneIndexer avmIndexer = getIndexer(to); + if (avmIndexer != null) + { + avmIndexer.createIndex(to, IndexMode.SYNCHRONOUS); + avmIndexer.index(to, 0, after, getIndexMode(to)); + } } return returnValue; } @@ -213,74 +213,76 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte { this.defaultMode = defaultMode; } - + + /** + * Is snapshot triggered indexing enabled + * + * @return true if indexing is enabled for AVM + */ + public boolean isIndexingEnabled() + { + return enableIndexing; + } + /** - * Is snapshot triggered indexing enabled - * - * @return true if indexing is enabled for AVM - */ - public boolean isIndexingEnabled() - { - return enableIndexing; - } - - /** * @param store * @param before * @param after */ public void indexSnapshot(String store, int before, int after) { - indexSnapshotImpl(store, before, after); + indexSnapshotImpl(store, before, after); } - - /** - * @param store - * @param after - */ + + /** + * @param store + * @param after + */ public void indexSnapshot(String store, int after) { - indexSnapshotImpl(store, -1, after); - } - - private void indexSnapshotImpl(String store, int before, int after) - { - if (getIndexMode(store) != IndexMode.UNINDEXED) + indexSnapshotImpl(store, -1, after); + } + + private void indexSnapshotImpl(String store, int before, int after) + { + if (getIndexMode(store) != IndexMode.UNINDEXED) { - AVMLuceneIndexer avmIndexer = getIndexer(store); - if (avmIndexer != null) - { - int last = getLastIndexedSnapshot(avmIndexer, store); - - if ((last == -1) && (! hasIndexBeenCreated(store))) - { - createIndex(store); - } - - avmIndexer.index(store, (before != -1 ? before : last), after, getIndexMode(store)); - } + AVMLuceneIndexer avmIndexer = getIndexer(store); + if (avmIndexer != null) + { + int last = getLastIndexedSnapshot(avmIndexer, store); + + if ((last == -1) && (! hasIndexBeenCreated(store))) + { + createIndex(store); + } + + int from = before != -1 ? before : last; + avmIndexer.index(store, from, after, getIndexMode(store)); + } } } - + /** * @param store * @return - the last indexed snapshot */ public int getLastIndexedSnapshot(String store) { - AVMLuceneIndexer avmIndexer = getIndexer(store); - if (avmIndexer != null) + + AVMLuceneIndexer avmIndexer = getIndexer(store); + if (avmIndexer != null) { - return getLastIndexedSnapshot(avmIndexer, store); + return getLastIndexedSnapshot(avmIndexer, store); } return -1; } - - private int getLastIndexedSnapshot(AVMLuceneIndexer avmIndexer, String store) - { - return avmIndexer.getLastIndexedSnapshot(store); - } - + + private int getLastIndexedSnapshot(AVMLuceneIndexer avmIndexer, String store) + { + return avmIndexer.getLastIndexedSnapshot(store); + } + /** * Is the snapshot applied to the index? Is there an entry for any node that was added OR have all the nodes in the * transaction been deleted as expected? @@ -291,8 +293,8 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte */ public boolean isSnapshotIndexed(String store, int id) { - AVMLuceneIndexer avmIndexer = getIndexer(store); - if (avmIndexer != null) + AVMLuceneIndexer avmIndexer = getIndexer(store); + if (avmIndexer != null) { return avmIndexer.isSnapshotIndexed(store, id); } @@ -315,8 +317,8 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte case SYNCHRONOUS: case ASYNCHRONOUS: int last = avmService.getLatestSnapshotID(store); - AVMLuceneIndexer avmIndexer = getIndexer(store); - if (avmIndexer != null) + AVMLuceneIndexer avmIndexer = getIndexer(store); + if (avmIndexer != null) { avmIndexer.flushPending(); return avmIndexer.isSnapshotSearchable(store, last); @@ -343,11 +345,11 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte case SYNCHRONOUS: case ASYNCHRONOUS: int last = avmService.getLatestSnapshotID(store); - AVMLuceneIndexer avmIndexer = getIndexer(store); - if (avmIndexer != null) + AVMLuceneIndexer avmIndexer = getIndexer(store); + if (avmIndexer != null) { avmIndexer.flushPending(); - return getLastIndexedSnapshot(avmIndexer, store) == last; + return avmIndexer.isSnapshotIndexed(store, last); } return false; default: @@ -487,8 +489,8 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte public boolean hasIndexBeenCreated(String store) { - AVMLuceneIndexer avmIndexer = getIndexer(store); - if (avmIndexer != null) + AVMLuceneIndexer avmIndexer = getIndexer(store); + if (avmIndexer != null) { avmIndexer.flushPending(); return avmIndexer.hasIndexBeenCreated(store); @@ -498,8 +500,8 @@ public class AVMSnapShotTriggeredIndexingMethodInterceptor implements MethodInte public void createIndex(String store) { - AVMLuceneIndexer avmIndexer = getIndexer(store); - if (avmIndexer != null) + AVMLuceneIndexer avmIndexer = getIndexer(store); + if (avmIndexer != null) { avmIndexer.createIndex(store, IndexMode.SYNCHRONOUS); } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexer.java b/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexer.java index 48f2806ec3..4d882050c6 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexer.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexer.java @@ -18,8 +18,11 @@ */ package org.alfresco.repo.search.impl.lucene; +import java.util.List; + import org.alfresco.repo.search.BackgroundIndexerAware; import org.alfresco.repo.search.IndexMode; +import org.alfresco.service.cmr.avm.VersionDescriptor; /** * AVM specific indxer support @@ -56,17 +59,6 @@ public interface AVMLuceneIndexer extends LuceneIndexer, BackgroundIndexerAware */ public void createIndex(String store, IndexMode mode); - /** - * Get the id of the last snapshot added to the index - * @param store - * - * @param mode - * - IndexMode.SYNCHRONOUS - the last searchable snapshop - * - IndexMode.ASYNCHRONOUS - the last pending snapshot to be indexed. It may or may not be searchable. - * @return - the snapshot id - */ - public int getLastIndexedSnapshot(String store); - /** * Is the snapshot applied to the index? * @@ -99,4 +91,12 @@ public interface AVMLuceneIndexer extends LuceneIndexer, BackgroundIndexerAware * @return */ public long getIndexedDocCount(); + + /** + * Get the last snapshot in the index - this does not mean that all snapshots before it have been indexed. + * + * @param store + * @return + */ + public int getLastIndexedSnapshot(String store); } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java index fcb51cf957..96f7bdd5a0 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java @@ -59,6 +59,7 @@ import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.service.cmr.avm.AVMException; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.VersionDescriptor; import org.alfresco.service.cmr.avmsync.AVMDifference; import org.alfresco.service.cmr.avmsync.AVMSyncException; import org.alfresco.service.cmr.avmsync.AVMSyncService; @@ -129,7 +130,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl private int startVersion = -1; private int endVersion = -1; - + private long indexedDocCount = 0; /** @@ -281,7 +282,12 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl } else { - index(difference.getDestinationPath()); + if (s_logger.isDebugEnabled()) + { + s_logger.debug("new: ("+srcVersion+", "+dstVersion+") "+difference.getDestinationPath()); + } + // AR-786 + reindex(difference.getDestinationPath(), dstDesc.isDirectory()); if (dstDesc.isDirectory()) { indexDirectory(dstDesc); @@ -289,13 +295,6 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl reindexAllAncestors(difference.getDestinationPath()); } } - // New Delete - else if (!srcDesc.isDeleted() && ((dstDesc == null) || dstDesc.isDeleted())) - { - delete(difference.getSourcePath()); - delete(difference.getDestinationPath()); - reindexAllAncestors(difference.getDestinationPath()); - } // Existing delete else if (srcDesc.isDeleted()) { @@ -311,7 +310,12 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl { // We are back from the dead ...the node used to be deleted // Treat as new - index(difference.getDestinationPath()); + // AR-786 + if (s_logger.isDebugEnabled()) + { + s_logger.debug("back: ("+srcVersion+", "+dstVersion+") "+difference.getDestinationPath()); + } + reindex(difference.getDestinationPath(), dstDesc.isDirectory()); if (dstDesc.isDirectory()) { indexDirectory(dstDesc); @@ -319,18 +323,49 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl reindexAllAncestors(difference.getDestinationPath()); } } - // Anything else then we reindex + // Anything else then we have a delete or reindex else { - if (!difference.getSourcePath().equals(difference.getDestinationPath())) + // Unknown end state ... + if(dstDesc == null) { + // we do not know what has happened - whatever it is does not apply to this snapshot + if (s_logger.isDebugEnabled()) + { + s_logger.debug("unknown: ("+srcVersion+", "+dstVersion+") "+difference.getDestinationPath()); + } + } + // Delete + else if (dstDesc.isDeleted()) + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("delete: ("+srcVersion+", "+dstVersion+") "+difference.getDestinationPath()); + } + delete(difference.getSourcePath()); + reindexAllAncestors(difference.getSourcePath()); + delete(difference.getDestinationPath()); + reindexAllAncestors(difference.getDestinationPath()); + } + // move + else if (!difference.getSourcePath().equals(difference.getDestinationPath())) + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("move: ("+srcVersion+", "+dstVersion+") "+difference.getDestinationPath()); + } reindex(difference.getSourcePath(), srcDesc.isDirectory()); reindex(difference.getDestinationPath(), dstDesc.isDirectory()); reindexAllAncestors(difference.getSourcePath()); reindexAllAncestors(difference.getDestinationPath()); } + // update else { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("update: ("+srcVersion+", "+dstVersion+") "+difference.getDestinationPath()); + } // If it is a directory, it is at the same path, // so no cascade update is required for the bridge table data. reindex(difference.getDestinationPath(), false); @@ -382,10 +417,12 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl private void indexDirectory(AVMNodeDescriptor dir) { - Map children = avmService.getDirectoryListing(dir); + Map children = avmService.getDirectoryListing(dir, false); for (AVMNodeDescriptor child : children.values()) { - index(child.getPath()); + // AR-786 + reindex(child.getPath(), child.isDirectory()); + reindexAllAncestors(child.getPath()); if (child.isDirectory()) { indexDirectory(child); @@ -542,7 +579,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl } else - // not a root node + // not a root node { xdoc.add(new Field("QNAME", qNameBuffer.toString(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.NO)); @@ -755,7 +792,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl if (isContent) { // Content is always tokenised - + ContentData contentData = DefaultTypeConverter.INSTANCE.convert(ContentData.class, serializableValue); if (!index || contentData.getMimetype() == null) { @@ -878,7 +915,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl } } else - // URL not present (null reader) or no content at the URL (file missing) + // URL not present (null reader) or no content at the URL (file missing) { // log it if (s_logger.isDebugEnabled()) @@ -898,20 +935,20 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl if (index) { - switch (tokenise) { - case TRUE: - case BOTH: - default: - fieldIndex = Field.Index.TOKENIZED; - break; - case FALSE: - fieldIndex = Field.Index.UN_TOKENIZED; - break; + switch (tokenise) { + case TRUE: + case BOTH: + default: + fieldIndex = Field.Index.TOKENIZED; + break; + case FALSE: + fieldIndex = Field.Index.UN_TOKENIZED; + break; - } - } else { - fieldIndex = Field.Index.NO; - } + } + } else { + fieldIndex = Field.Index.NO; + } if ((fieldIndex != Field.Index.NO) || (fieldStore != Field.Store.NO)) { @@ -956,7 +993,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl { doc.add(new Field(attributeName, t.termText(), Field.Store.NO, Field.Index.NO_NORMS, Field.TermVector.NO)); } - + doc.add(new Field(attributeName, t.termText(), Field.Store.NO, Field.Index.NO_NORMS, Field.TermVector.NO)); } @@ -1027,7 +1064,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl { locale = I18NUtil.getLocale(); } - + StringBuilder builder; MLAnalysisMode analysisMode; VerbatimAnalyser vba; @@ -1063,7 +1100,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl { doc.add(new Field(attributeName, t.termText(), Field.Store.NO, Field.Index.NO_NORMS, Field.TermVector.NO)); } - + doc.add(new Field(attributeName, t.termText(), Field.Store.NO, Field.Index.NO_NORMS, Field.TermVector.NO)); } } @@ -1132,7 +1169,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl break; case BOTH: doc.add(new Field(attributeName, strValue, fieldStore, fieldIndex, Field.TermVector.NO)); - + df = CachingDateFormat.getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", true); try { @@ -1161,15 +1198,15 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl @Override protected void doPrepare() throws IOException { - AuthenticationUtil.runAs(new RunAsWork() - { + AuthenticationUtil.runAs(new RunAsWork() + { public String doWork() throws Exception { - saveDelta(); - flushPending(); - return null; + saveDelta(); + flushPending(); + return null; } - }, AuthenticationUtil.getSystemUserName()); + }, AuthenticationUtil.getSystemUserName()); } @Override @@ -1542,6 +1579,301 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl this.fullTextSearchIndexer = fullTextSearchIndexer; } + + public boolean isSnapshotIndexed(String store, int id) + { + if (id == 0) + { + return hasIndexBeenCreated(store); + } + else + { + return isSynchronousSnapshotPresent(store, id) || isSynchronousSnapshotPresent(store, id); + } + } + + private boolean isSynchronousSnapshotPresent(String store, int id) + { + return isSynchronousSnapshotPresent(store, IndexChannel.MAIN, id) || isSynchronousSnapshotPresent(store, IndexChannel.DELTA, id) ; + } + + private boolean isAsynchronousSnapshotPresent(String store, int id) + { + return isAsynchronousSnapshotPresent(store, IndexChannel.MAIN, id) || isAsynchronousSnapshotPresent(store, IndexChannel.DELTA, id) ; + } + + public boolean isSnapshotSearchable(String store, int id) + { + if (id == 0) + { + return hasIndexBeenCreated(store); + } + else + { + return isSynchronousSnapshotPresent(store, id); + } + } + + + private boolean isSynchronousSnapshotPresent(String store, IndexChannel channel, int snapshot) + { + String prefix = SNAP_SHOT_ID + ":" + store + ":"; + IndexReader reader = null; + try + { + if (channel == IndexChannel.DELTA) + { + flushPending(); + reader = getDeltaReader(); + } + else + { + reader = getReader(); + } + + TermEnum terms = null; + try + { + terms = reader.terms(new Term("ID", prefix)); + if (terms.term() != null) + { + do + { + Term term = terms.term(); + if (term.text().startsWith(prefix)) + { + TermDocs docs = null; + try + { + docs = reader.termDocs(term); + if (docs.next()) + { + String[] split = term.text().split(":"); + int test = Integer.parseInt(split[3]); + if (test == snapshot) + { + return true; + } + } + } + finally + { + if (docs != null) + { + docs.close(); + } + } + } + else + { + break; + } + } + while (terms.next()); + } + } + finally + { + if (terms != null) + { + terms.close(); + } + } + return false; + } + catch (IOException e) + { + throw new AlfrescoRuntimeException("IO error", e); + } + finally + { + try + { + if (reader != null) + { + if (channel == IndexChannel.DELTA) + { + closeDeltaReader(); + } + else + { + reader.close(); + } + } + } + catch (IOException e) + { + s_logger.warn("Failed to close main reader", e); + } + } + } + + private boolean isAsynchronousSnapshotPresent(String store, IndexChannel channel, int snapshot) + { + String prefix = "\u0000BG:STORE:" + store + ":"; + IndexReader reader = null; + try + { + if (channel == IndexChannel.DELTA) + { + flushPending(); + reader = getDeltaReader(); + } + else + { + reader = getReader(); + } + TermEnum terms = null; + try + { + terms = reader.terms(new Term("ID", prefix)); + if (terms.term() != null) + { + do + { + Term term = terms.term(); + if (term.text().startsWith(prefix)) + { + TermDocs docs = null; + try + { + docs = reader.termDocs(term); + if (docs.next()) + { + String[] split = term.text().split(":"); + int test = Integer.parseInt(split[4]); + if (test == snapshot) + { + return true; + } + } + } + finally + { + if (docs != null) + { + docs.close(); + } + } + + } + else + { + break; + } + } + while (terms.next()); + } + } + finally + { + if (terms != null) + { + terms.close(); + } + } + return false; + } + catch (IOException e) + { + throw new AlfrescoRuntimeException("IO error", e); + } + finally + { + try + { + if (reader != null) + { + if (channel == IndexChannel.DELTA) + { + closeDeltaReader(); + } + else + { + reader.close(); + } + } + } + catch (IOException e) + { + s_logger.warn("Failed to close main reader", e); + } + } + } + + + public boolean hasIndexBeenCreated(String store) + { + return hasIndexBeenCreatedimpl(store, IndexChannel.MAIN) || hasIndexBeenCreatedimpl(store, IndexChannel.DELTA); + } + + public boolean hasIndexBeenCreatedimpl(String store, IndexChannel channel) + { + IndexReader reader = null; + try + { + if (channel == IndexChannel.DELTA) + { + flushPending(); + reader = getDeltaReader(); + } + else + { + reader = getReader(); + } + TermDocs termDocs = null; + try + { + termDocs = reader.termDocs(new Term("ISROOT", "T")); + return termDocs.next(); + } + finally + { + if (termDocs != null) + { + termDocs.close(); + } + } + } + catch (IOException e) + { + throw new AlfrescoRuntimeException("IO error", e); + } + finally + { + try + { + + if (reader != null) + { + if (channel == IndexChannel.DELTA) + { + closeDeltaReader(); + } + else + { + reader.close(); + } + } + } + catch (IOException e) + { + s_logger.warn("Failed to close main reader", e); + } + } + + } + + public synchronized long getIndexedDocCount() + { + return indexedDocCount; + } + + private synchronized void incrementDocCount() + { + indexedDocCount++; + } + public int getLastIndexedSnapshot(String store) { int last = getLastAsynchronousSnapshot(store); @@ -1556,31 +1888,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl } return hasIndexBeenCreated(store) ? 0 : -1; } - - public boolean isSnapshotIndexed(String store, int id) - { - if (id == 0) - { - return hasIndexBeenCreated(store); - } - else - { - return (id <= getLastAsynchronousSnapshot(store)) || (id <= getLastSynchronousSnapshot(store)); - } - } - - public boolean isSnapshotSearchable(String store, int id) - { - if (id == 0) - { - return hasIndexBeenCreated(store); - } - else - { - return (id <= getLastSynchronousSnapshot(store)); - } - } - + private int getLastSynchronousSnapshot(String store) { int answer = getLastSynchronousSnapshot(store, IndexChannel.DELTA); @@ -1798,76 +2106,4 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl } } } - - public boolean hasIndexBeenCreated(String store) - { - return hasIndexBeenCreatedimpl(store, IndexChannel.MAIN) || hasIndexBeenCreatedimpl(store, IndexChannel.DELTA); - } - - public boolean hasIndexBeenCreatedimpl(String store, IndexChannel channel) - { - IndexReader reader = null; - try - { - if (channel == IndexChannel.DELTA) - { - flushPending(); - reader = getDeltaReader(); - } - else - { - reader = getReader(); - } - TermDocs termDocs = null; - try - { - termDocs = reader.termDocs(new Term("ISROOT", "T")); - return termDocs.next(); - } - finally - { - if (termDocs != null) - { - termDocs.close(); - } - } - } - catch (IOException e) - { - throw new AlfrescoRuntimeException("IO error", e); - } - finally - { - try - { - - if (reader != null) - { - if (channel == IndexChannel.DELTA) - { - closeDeltaReader(); - } - else - { - reader.close(); - } - } - } - catch (IOException e) - { - s_logger.warn("Failed to close main reader", e); - } - } - - } - - public synchronized long getIndexedDocCount() - { - return indexedDocCount; - } - - private synchronized void incrementDocCount() - { - indexedDocCount++; - } } diff --git a/source/java/org/alfresco/service/cmr/avm/AVMService.java b/source/java/org/alfresco/service/cmr/avm/AVMService.java index 42b1fc699c..572056c87f 100644 --- a/source/java/org/alfresco/service/cmr/avm/AVMService.java +++ b/source/java/org/alfresco/service/cmr/avm/AVMService.java @@ -1367,5 +1367,32 @@ public interface AVMService * @throws AVMWrongTypeException */ public void setContentData(String path, ContentData data); + + /** + * Get all versions from the last down to and including the one specified + * Returned in descending version id. + * @param name + * @param version + * @return list of version descriptors + */ + public List getStoreVersionsFrom(String name, int version); + + /** + * Get all versions from the first up to and including the one specified + * Returned in ascending version id order. + * @param name + * @param version + * @return list of version descriptors + */ + public List getStoreVersionsTo(String name, int version); + + /** + * Get all versions from an including startVersion up to but NOT including endVersion + * @param name + * @param startVersion + * @param endVersion + * @return list of version descriptors + */ + public List getStoreVersionsBetween(String name, int startVersion, int endVersion); }