Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: Implements a service for managing a Hazelcast cluster member
4
 *  Copyright: 2011 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Christopher Jones
7
 * 
8
 *   '$Author: leinfelder $'
9
 *     '$Date: 2012-05-31 10:13:29 -0700 (Thu, 31 May 2012) $'
10
 * '$Revision: 7216 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

    
27
package edu.ucsb.nceas.metacat.dataone.hazelcast;
28

    
29
import java.io.FileNotFoundException;
30
import java.sql.SQLException;
31
import java.util.HashSet;
32
import java.util.Iterator;
33
import java.util.List;
34
import java.util.Set;
35
import java.util.concurrent.ExecutorService;
36
import java.util.concurrent.Executors;
37
import java.util.concurrent.locks.Lock;
38

    
39
import org.apache.log4j.Logger;
40
import org.dataone.service.exceptions.InvalidSystemMetadata;
41
import org.dataone.service.types.v1.Identifier;
42
import org.dataone.service.types.v1.Node;
43
import org.dataone.service.types.v1.NodeReference;
44
import org.dataone.service.types.v1.SystemMetadata;
45

    
46
import com.hazelcast.config.Config;
47
import com.hazelcast.config.FileSystemXmlConfig;
48
import com.hazelcast.core.EntryEvent;
49
import com.hazelcast.core.EntryListener;
50
import com.hazelcast.core.Hazelcast;
51
import com.hazelcast.core.HazelcastInstance;
52
import com.hazelcast.core.IMap;
53
import com.hazelcast.core.ISet;
54
import com.hazelcast.core.LifecycleEvent;
55
import com.hazelcast.core.LifecycleListener;
56
import com.hazelcast.core.Member;
57
import com.hazelcast.core.MembershipEvent;
58
import com.hazelcast.core.MembershipListener;
59
import com.hazelcast.partition.Partition;
60
import com.hazelcast.partition.PartitionService;
61

    
62
import edu.ucsb.nceas.metacat.IdentifierManager;
63
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
64
import edu.ucsb.nceas.metacat.properties.PropertyService;
65
import edu.ucsb.nceas.metacat.shared.BaseService;
66
import edu.ucsb.nceas.metacat.shared.ServiceException;
67
import edu.ucsb.nceas.metacat.util.DocumentUtil;
68
import edu.ucsb.nceas.utilities.FileUtil;
69
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
70
/**
71
 * The Hazelcast service enables Metacat as a Hazelcast cluster member
72
 */
73
public class HazelcastService extends BaseService
74
  implements EntryListener<Identifier, SystemMetadata>, MembershipListener, LifecycleListener {
75
  
76
  private static final String SINCE_PROPERTY = "dateSysMetadataModified";
77

    
78
/* The instance of the logging class */
79
  private static Logger logMetacat = Logger.getLogger(HazelcastService.class);
80
  
81
  /* The singleton instance of the hazelcast service */
82
  private static HazelcastService hzService = null;
83
  
84
  /* The Hazelcast configuration */
85
  private Config hzConfig;
86
  
87
  /* The instance of the Hazelcast client */
88
//  private HazelcastClient hzClient;
89

    
90
  /* The name of the DataONE Hazelcast cluster group */
91
  private String groupName;
92

    
93
  /* The name of the DataONE Hazelcast cluster password */
94
  private String groupPassword;
95
  
96
  /* The name of the DataONE Hazelcast cluster IP addresses */
97
  private String addressList;
98
  
99
  /* The name of the node map */
100
  private String nodeMap;
101

    
102
  /* The name of the system metadata map */
103
  private String systemMetadataMap;
104
  
105
  /* The Hazelcast distributed task id generator namespace */
106
  private String taskIds;
107
  
108
  /* The Hazelcast distributed node map */
109
  private IMap<NodeReference, Node> nodes;
110

    
111
  /* The Hazelcast distributed system metadata map */
112
  private IMap<Identifier, SystemMetadata> systemMetadata;
113
  
114
  /* The name of the identifiers set */
115
  private String identifiersSet;
116
  
117
  /* The Hazelcast distributed identifiers set */
118
  private ISet<Identifier> identifiers;
119

    
120
  private HazelcastInstance hzInstance;
121
      
122
  /*
123
   * Constructor: Creates an instance of the hazelcast service. Since
124
   * this uses a singleton pattern, use getInstance() to gain the instance.
125
   */
126
  private HazelcastService() {
127
    
128
    super();
129
    _serviceName="HazelcastService";
130
    
131
    try {
132
      init();
133
      
134
    } catch (ServiceException se) {
135
      logMetacat.error("There was a problem creating the HazelcastService. " +
136
                       "The error message was: " + se.getMessage());
137
      
138
    }
139
    
140
  }
141
  
142
  /**
143
   *  Get the instance of the HazelcastService that has been instantiated,
144
   *  or instantiate one if it has not been already.
145
   *
146
   * @return hazelcastService - The instance of the hazelcast service
147
   */
148
  public static HazelcastService getInstance(){
149
    
150
    if ( hzService == null ) {
151
      
152
      hzService = new HazelcastService();
153
      
154
    }
155
    return hzService;
156
  }
157
  
158
  /**
159
   * Initializes the Hazelcast service
160
   */
161
  public void init() throws ServiceException {
162
    
163
    logMetacat.debug("HazelcastService.init() called.");
164
    
165
	String configFileName = null;
166
	Config config = null;
167
	try {
168
		configFileName = PropertyService.getProperty("dataone.hazelcast.configFilePath");
169
		config = new FileSystemXmlConfig(configFileName);
170
	} catch (Exception e) {
171
		configFileName = PropertyService.CONFIG_FILE_DIR + FileUtil.getFS() + "hazelcast.xml";
172
		logMetacat.warn("Custom Hazelcast configuration not defined, using default: " + configFileName);
173
		// make sure we have the config
174
		try {
175
			config = new FileSystemXmlConfig(configFileName);
176
		} catch (FileNotFoundException e1) {
177
			String msg = e.getMessage();
178
			logMetacat.error(msg);
179
			throw new ServiceException(msg);
180
		}
181
	}
182

    
183
	Hazelcast.init(config);
184
	this.hzInstance = Hazelcast.getDefaultInstance();
185
  
186
  	logMetacat.debug("Initialized hzInstance");
187

    
188
    // Get configuration properties on instantiation
189
    try {
190
      groupName = 
191
        PropertyService.getProperty("dataone.hazelcast.processCluster.groupName");
192
      groupPassword = 
193
        PropertyService.getProperty("dataone.hazelcast.processCluster.password");
194
      addressList = 
195
        PropertyService.getProperty("dataone.hazelcast.processCluster.instances");
196
      systemMetadataMap = 
197
        PropertyService.getProperty("dataone.hazelcast.storageCluster.systemMetadataMap");
198
      identifiersSet = PropertyService.getProperty("dataone.hazelcast.storageCluster.identifiersSet");
199
//    nodeMap = 
200
//    PropertyService.getProperty("dataone.hazelcast.processCluster.nodesMap");
201
      // Become a DataONE-process cluster client
202
//      String[] addresses = addressList.split(",");
203
//      hzClient = 
204
//        HazelcastClient.newHazelcastClient(this.groupName, this.groupPassword, addresses);
205
//      nodes = hzClient.getMap(nodeMap);
206
      
207
      // Get a reference to the shared system metadata map as a cluster member
208
      // NOTE: this loads the map from the backing store and can take a long time for large collections
209
      systemMetadata = Hazelcast.getMap(systemMetadataMap);
210
      
211
      logMetacat.debug("Initialized systemMetadata");
212

    
213
      // Get a reference to the shared identifiers set as a cluster member
214
      // NOTE: this takes a long time to complete
215
      identifiers = Hazelcast.getSet(identifiersSet);
216
      logMetacat.debug("got identifiersSet");
217
      
218
      identifiers.addAll(loadAllKeys());
219
      logMetacat.debug("Initialized identifiers");
220
      
221
      // Listen for changes to the system metadata map
222
      systemMetadata.addEntryListener(this, true);
223
      
224
      // Listen for members added/removed
225
      hzInstance.getCluster().addMembershipListener(this);
226
      
227
      // Listen for lifecycle state changes
228
      hzInstance.getLifecycleService().addLifecycleListener(this);
229
      
230
    } catch (PropertyNotFoundException e) {
231

    
232
      String msg = "Couldn't find Hazelcast properties for the DataONE clusters. " +
233
        "The error message was: " + e.getMessage();
234
      logMetacat.error(msg);
235
      
236
    }
237
    
238
    // make sure we have all metadata locally
239
    try {
240
    	// synch on restart
241
        resynchInThread();
242
	} catch (Exception e) {
243
		String msg = "Problem resynchronizing system metadata. " + e.getMessage();
244
		logMetacat.error(msg, e);
245
	}
246
        
247
  }
248
  
249
  /**
250
   * Get the system metadata map
251
   * 
252
   * @return systemMetadata - the hazelcast map of system metadata
253
   * @param identifier - the identifier of the object as a string
254
   */
255
  public IMap<Identifier,SystemMetadata> getSystemMetadataMap() {
256
	  return systemMetadata;
257
  }
258
  
259
  /**
260
   * Get the identifiers set
261
   * @return identifiers - the set of unique DataONE identifiers in the cluster
262
   */
263
  public ISet<Identifier> getIdentifiers() {
264
      return identifiers;
265
      
266
  }
267

    
268
  /**
269
   * When Metacat changes the underlying store, we need to refresh the
270
   * in-memory representation of it.
271
   * @param guid
272
   */
273
  public void refreshSystemMetadataEntry(String guid) {
274
	Identifier identifier = new Identifier();
275
	identifier.setValue(guid);
276
	// force hazelcast to update system metadata in memory from the store
277
	HazelcastService.getInstance().getSystemMetadataMap().evict(identifier);
278
	
279
  }
280

    
281
  public Lock getLock(String identifier) {
282
    
283
    Lock lock = null;
284
    
285
    try {
286
        lock = getInstance().getHazelcastInstance().getLock(identifier);
287
        
288
    } catch (RuntimeException e) {
289
        logMetacat.info("Couldn't get a lock for identifier " + 
290
            identifier + " !!");
291
    }
292
    return lock;
293
      
294
  }
295
  
296
  /**
297
   * Get the DataONE hazelcast node map
298
   * @return nodes - the hazelcast map of nodes
299
   */
300
//  public IMap<NodeReference, Node> getNodesMap() {
301
//	  return nodes;
302
//  }
303
  
304
  /**
305
   * Indicate whether or not this service is refreshable.
306
   *
307
   * @return refreshable - the boolean refreshable status
308
   */
309
  public boolean refreshable() {
310
    // TODO: Determine the consequences of restarting the Hazelcast instance
311
    // Set this to true if it's okay to drop from the cluster, lose the maps,
312
    // and start back up again
313
    return false;
314
    
315
  }
316
  
317
  /**
318
   * Stop the HazelcastService. When stopped, the service will no longer
319
   * respond to requests.
320
   */
321
  public void stop() throws ServiceException {
322
    
323
    Hazelcast.getLifecycleService().shutdown();
324
    
325
  }
326

    
327
  public HazelcastInstance getHazelcastInstance() {
328
      return this.hzInstance;
329
      
330
  }
331
  
332
  /**
333
   * Refresh the Hazelcast service by restarting it
334
   */
335
  @Override
336
  protected void doRefresh() throws ServiceException {
337

    
338
    // TODO: verify that the correct config file is still used
339
    Hazelcast.getLifecycleService().restart();
340
    
341
  }
342
  
343
  /**
344
	 * Implement the EntryListener interface for Hazelcast, reponding to entry
345
	 * added events in the hzSystemMetadata map. Evaluate the entry and create
346
	 * CNReplicationTasks as appropriate (for DATA, METADATA, RESOURCE)
347
	 * 
348
	 * @param event - The EntryEvent that occurred
349
	 */
350
	@Override
351
	public void entryAdded(EntryEvent<Identifier, SystemMetadata> event) {
352
	  
353
	  logMetacat.info("SystemMetadata entry added event on identifier " + 
354
	      event.getKey().getValue());
355
		// handle as update - that method will create if necessary
356
		entryUpdated(event);
357

    
358
	}
359

    
360
	/**
361
	 * Implement the EntryListener interface for Hazelcast, reponding to entry
362
	 * evicted events in the hzSystemMetadata map.  Evaluate the entry and create
363
	 * CNReplicationTasks as appropriate (for DATA, METADATA, RESOURCE)
364
	 * 
365
	 * @param event - The EntryEvent that occurred
366
	 */
367
	@Override
368
	public void entryEvicted(EntryEvent<Identifier, SystemMetadata> event) {
369

    
370
      logMetacat.info("SystemMetadata entry evicted event on identifier " + 
371
          event.getKey().getValue());
372
      
373
	    // ensure identifiers are listed in the hzIdentifiers set
374
      if ( !identifiers.contains(event.getKey()) ) {
375
          identifiers.add(event.getKey());
376
      }
377
	  
378
	}
379
	
380
	/**
381
	 * Implement the EntryListener interface for Hazelcast, reponding to entry
382
	 * removed events in the hzSystemMetadata map.  Evaluate the entry and create
383
	 * CNReplicationTasks as appropriate (for DATA, METADATA, RESOURCE)
384
	 * 
385
	 * @param event - The EntryEvent that occurred
386
	 */
387
	@Override
388
	public void entryRemoved(EntryEvent<Identifier, SystemMetadata> event) {
389
		
390
    logMetacat.info("SystemMetadata entry removed event on identifier " + 
391
        event.getKey().getValue());
392

    
393
	  // we typically don't remove objects in Metacat, but can remove System Metadata
394
		IdentifierManager.getInstance().deleteSystemMetadata(event.getValue().getIdentifier().getValue());
395

    
396
    // keep the hzIdentifiers set in sync with the systemmetadata table
397
    if ( identifiers.contains(event.getKey()) ) {
398
        identifiers.remove(event.getKey());
399
        
400
    }
401

    
402
	}
403
	
404
	/**
405
	 * Implement the EntryListener interface for Hazelcast, reponding to entry
406
	 * updated events in the hzSystemMetadata map.  Evaluate the entry and create
407
	 * CNReplicationTasks as appropriate (for DATA, METADATA, RESOURCE)
408
	 * 
409
	 * @param event - The EntryEvent that occurred
410
	 */
411
	@Override
412
	public void entryUpdated(EntryEvent<Identifier, SystemMetadata> event) {
413

    
414
		logMetacat.debug("Entry added/updated to System Metadata map: " + event.getKey().getValue());
415
		PartitionService partitionService = Hazelcast.getPartitionService();
416
		Partition partition = partitionService.getPartition(event.getKey());
417
		Member ownerMember = partition.getOwner();
418
		SystemMetadata sysmeta = event.getValue();
419
		if (!ownerMember.localMember()) {
420
			if (sysmeta == null) {
421
				logMetacat.warn("No SystemMetadata provided in the event, getting from shared map: " + event.getKey().getValue());
422
				sysmeta = getSystemMetadataMap().get(event.getKey());
423
				if (sysmeta == null) {
424
					// this is a problem
425
					logMetacat.error("Could not find SystemMetadata in shared map for: " + event.getKey().getValue());
426
					// TODO: should probably return at this point since the save will fail
427
				}
428
			}
429
			// need to pull the entry into the local store
430
			saveLocally(event.getValue());
431
		}
432

    
433
		// ensure identifiers are listed in the hzIdentifiers set
434
		if (!identifiers.contains(event.getKey())) {
435
			identifiers.add(event.getKey());
436
		}
437

    
438
	}
439
	
440
	/**
441
	 * Save SystemMetadata to local store if needed
442
	 * @param sm
443
	 */
444
	private void saveLocally(SystemMetadata sm) {
445
		logMetacat.debug("Saving entry locally: " + sm.getIdentifier().getValue());
446
		try {
447

    
448
			IdentifierManager.getInstance().insertOrUpdateSystemMetadata(sm);
449

    
450
		} catch (McdbDocNotFoundException e) {
451
			logMetacat.error("Could not save System Metadata to local store.", e);
452
			
453
		} catch (SQLException e) {
454
	      logMetacat.error("Could not save System Metadata to local store.", e);
455
	      
456
	    } catch (InvalidSystemMetadata e) {
457
	        logMetacat.error("Could not save System Metadata to local store.", e);
458
	        
459
	    }
460
	}
461
	
462
	/**
463
	 * Checks the local backing store for missing SystemMetadata,
464
	 * retrieves those entries from the shared map if they exist,
465
	 * and saves them locally.
466
	 */
467
	private void synchronizeLocalStore() {
468
		List<String> localIds = IdentifierManager.getInstance().getLocalIdsWithNoSystemMetadata(true, -1);
469
		if (localIds != null) {
470
			logMetacat.debug("Member missing SystemMetadata entries, count = " + localIds.size());
471
			for (String localId: localIds) {
472
				logMetacat.debug("Processing system metadata for localId: " + localId);
473
				try {
474
					String docid = DocumentUtil.getSmartDocId(localId);
475
					int rev = DocumentUtil.getRevisionFromAccessionNumber(localId);
476
					String guid = IdentifierManager.getInstance().getGUID(docid, rev);
477
					logMetacat.debug("Found mapped guid: " + guid);
478
					Identifier pid = new Identifier();
479
					pid.setValue(guid);
480
					SystemMetadata sm = systemMetadata.get(pid);
481
					logMetacat.debug("Found shared system metadata for guid: " + guid);
482
					saveLocally(sm);
483
					logMetacat.debug("Saved shared system metadata locally for guid: " + guid);
484
				} catch (Exception e) {
485
					logMetacat.error("Could not save shared SystemMetadata entry locally, localId: " + localId, e);
486
				}
487
			}
488
		}
489
	}
490
	
491
	/**
492
	 * Make sure we have a copy of every entry in the shared map.
493
	 * We use lazy loading and therefore the CNs may not all be in sync when one
494
	 * comes back online after an extended period of being offline
495
	 * This method is meant to retrieve shared SystemMetadata that does not exist locally.
496
	 * A mak=jor shortcoming here is that if Hazelcast has assigned this node ownership of a PID
497
	 * that does not exist on the local backing store, the SystemMetadata will be null.
498
	 * @throws Exception
499
	 * @deprecated
500
	 */
501
	private void resynch() throws Exception {
502
		// loop through all the [shared] entries and save any missing ones locally
503
		List<String> localPids = IdentifierManager.getInstance().getAllSystemMetadataGUIDs();
504
		logMetacat.warn("local pid count: " + localPids.size() + ", shared pid count: " + identifiers.size());
505
		Iterator<Identifier> sharedPids = identifiers.iterator();
506
		while (sharedPids.hasNext()) {
507
			Identifier pid = sharedPids.next();
508
			logMetacat.trace("checking for shared pid locally: " + pid.getValue());
509
			if (!localPids.contains(pid.getValue())) {
510
				logMetacat.warn("shared pid does not exist locally: " + pid.getValue());
511
				SystemMetadata sm = systemMetadata.get(pid);
512
				if (sm != null) {
513
					// this may throw an exception if loading it to the shared map triggered entry updated events
514
					saveLocally(sm);
515
				} else {
516
					logMetacat.error("SystemMetadata for pid is null: " + pid.getValue());
517
					Partition partition = hzInstance.getPartitionService().getPartition(pid);
518
					Member owner = partition.getOwner();
519
					owner.localMember();
520
					logMetacat.warn("owner of pid: " + pid.getValue() + " isLocal: " + owner.localMember() + " at " + owner.getInetSocketAddress().getAddress());
521

    
522
				}
523
			} else {
524
				logMetacat.trace("shared pid already exisits locally: " + pid.getValue());
525
			}
526
		}
527
	}
528
	
529
	/**
530
	 * Make sure we have a copy of every entry in the shared map.
531
	 * We use lazy loading and therefore the CNs may not all be in sync when one
532
	 * comes back online after an extended period of being offline
533
	 * This method loops through the entries that a FULLY UP-TO-DATE CN has
534
	 * and makes sure each one is present on the shared map.
535
	 * It is meant to overcome a HZ weakness wherein ownership of a key results in 
536
	 * null values where the owner does not have a complete backing store.
537
	 * This will be an expensive routine and should be run in a background process so that
538
	 * the server can continue to service other requests during the synch
539
	 * @throws Exception
540
	 */
541
	private void resynchToRemote() throws Exception {
542
		// loop through all the [shared] entries and save any missing ones locally
543
		List<String> localPids = IdentifierManager.getInstance().getAllSystemMetadataGUIDs();
544
		logMetacat.warn("local pid count: " + localPids.size() + ", shared pid count: " + identifiers.size());
545
		
546
		//loop through all the pids to find any nulls
547
		Iterator<Identifier> sharedPids = identifiers.iterator();
548
		while (sharedPids.hasNext()) {
549
			Identifier pid = sharedPids.next();
550
			logMetacat.trace("looking up shared value for pid: " + pid.getValue());
551
			SystemMetadata sm = systemMetadata.get(pid);
552
			if (sm == null)  {
553
				logMetacat.warn("shared SystemMetadata for pid is null: " + pid.getValue());
554
				// look up owner of the pid
555
				Partition partition = hzInstance.getPartitionService().getPartition(pid);
556
				Member owner = partition.getOwner();
557
				boolean isLocalPid = owner.localMember();
558
				logMetacat.debug("owner of pid: " + pid.getValue() + " isLocal: " + isLocalPid);
559
				// if we don't own it, we can look it up locally in hopes that we have our own copy
560
				if (!isLocalPid) {
561
					// get directly from backing store
562
					sm = IdentifierManager.getInstance().getSystemMetadata(pid.getValue());
563
					if (sm != null)  {
564
						logMetacat.debug("saving local SystemMetadata to shared map for pid: " + pid.getValue());
565
						systemMetadata.put(pid, sm);
566
					} else {
567
						logMetacat.error("local SystemMetadata is null for pid: " + pid.getValue());
568
					}
569
				}
570
			}
571
		}
572
		
573
	}
574
	
575
	private void resynchInThread() {
576
		logMetacat.debug("launching system metadata resynch in a thread");
577
		ExecutorService executor = Executors.newSingleThreadExecutor();
578
		executor.execute(new Runnable() {
579
			@Override
580
			public void run() {
581
				try {
582
					// this is a pull mechanism
583
					//resynch();
584
					// this is a push mechanism
585
					resynchToRemote();
586
				} catch (Exception e) {
587
					logMetacat.error("Error in resynchInThread: " + e.getMessage(), e);
588
				}
589
			}
590
		});
591
		executor.shutdown();
592
	}
593

    
594
	/**
595
	 * When there is missing SystemMetadata on the local member,
596
	 * we retrieve it from the shared map and add it to the local
597
	 * backing store for safe keeping.
598
	 */
599
	@Override
600
	public void memberAdded(MembershipEvent event) {
601
		Member member = event.getMember();
602
		logMetacat.debug("Member added to cluster: " + member.getInetSocketAddress());
603
		boolean isLocal = member.localMember();
604
		if (isLocal) {
605
			logMetacat.debug("Member islocal: " + member.getInetSocketAddress());
606
			synchronizeLocalStore();
607
		}
608
	}
609

    
610
	@Override
611
	public void memberRemoved(MembershipEvent event) {
612
		// TODO Auto-generated method stub
613
		
614
	}
615

    
616
	/**
617
	 * In cases where this cluster is paused, we want to 
618
	 * check that the local store accurately reflects the shared 
619
	 * SystemMetadata map
620
	 * @param event
621
	 */
622
	@Override
623
	public void stateChanged(LifecycleEvent event) {
624
		logMetacat.debug("HZ LifecycleEvent.state: " + event.getState());
625
		if (event.getState().equals(LifecycleEvent.LifecycleState.RESUMED)) {
626
			logMetacat.debug("HZ LifecycleEvent.state is RESUMED, calling synchronizeLocalStore()");
627
			synchronizeLocalStore();
628
		}
629
	}
630

    
631
	/**
632
	 * Load all System Metadata keys from the backing store
633
	 * @return set of pids
634
	 */
635
	private Set<Identifier> loadAllKeys() {
636

    
637
		Set<Identifier> pids = new HashSet<Identifier>();
638
		
639
		try {
640
			
641
			// ALTERNATIVE 1: this has more overhead than just looking at the GUIDs
642
//			ObjectList ol = IdentifierManager.getInstance().querySystemMetadata(
643
//					null, //startTime, 
644
//					null, //endTime, 
645
//					null, //objectFormatId, 
646
//					false, //replicaStatus, 
647
//					0, //start, 
648
//					-1 //count
649
//					);
650
//			for (ObjectInfo o: ol.getObjectInfoList()) {
651
//				Identifier pid = o.getIdentifier();
652
//				if ( !pids.contains(pid) ) {
653
//					pids.add(pid);
654
//				}				
655
//			}
656
			
657
			// ALTERNATIVE method: look up all the Identifiers from the table
658
			List<String> guids = IdentifierManager.getInstance().getAllSystemMetadataGUIDs();
659
			logMetacat.warn("Local SystemMetadata pid count: " + guids.size());
660
			for (String guid: guids){
661
				Identifier pid = new Identifier();
662
				pid.setValue(guid);
663
				pids.add(pid);
664
			}
665
			
666
		} catch (Exception e) {
667
			throw new RuntimeException(e.getMessage(), e);
668
			
669
		}
670
		
671
		return pids;
672
	}
673

    
674
}
(1-1/3)