Changeset 5280


Ignore:
Timestamp:
2011-12-19 16:24:00 (17 months ago)
Author:
evert
Message:

Schema Cache:

  • Catch any exception when checking the lilyNodes on zookeeper instead of only the NoNodeException?, and log at Debug level.
  • Keep track of locally updated FieldTypes? and avoid overwriting them with old data when refreshing the cache. This manifests itself in the rename FieldType? test.
Location:
trunk/cr/repository
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/cr/repository/impl/src/main/java/org/lilyproject/repository/impl/AbstractSchemaCache.java

    r5271 r5280  
    4747    private FieldTypes fieldTypesSnapshot; 
    4848    private FieldTypesCache fieldTypesCache = new FieldTypesCache(); 
    49     private boolean updatedFieldTypes = false; 
     49    private volatile boolean updatedFieldTypes = false; 
    5050 
    5151    private RecordTypesCache recordTypes = new RecordTypesCache(); 
     
    438438                lilyNodes = zooKeeper.getChildren(LILY_NODES_PATH, watcher); 
    439439                lilyNodesWatcher = watcher; 
    440             } catch (KeeperException.NoNodeException e) { 
     440            } catch (KeeperException e) { 
     441                if (log.isDebugEnabled()) 
     442                    log.debug("Failed getting lilyNodes from Zookeeper", e); 
    441443                // The path does not exist yet. 
    442444                // Set the lilyNodesWatcher to null so that we retry 
  • trunk/cr/repository/impl/src/main/java/org/lilyproject/repository/impl/FieldTypesCache.java

    r5256 r5280  
    1717 
    1818import java.util.HashMap; 
     19import java.util.HashSet; 
    1920import java.util.List; 
    2021import java.util.Map; 
    2122import java.util.Map.Entry; 
     23import java.util.Set; 
    2224import java.util.concurrent.ConcurrentHashMap; 
    2325 
     
    4244    // lead to an inconsistent state (two types could get the same name). 
    4345    private volatile int count = 0; 
     46     
     47    private ConcurrentHashMap<String, Set<SchemaId>> localUpdateBuckets = new ConcurrentHashMap<String, Set<SchemaId>>(); 
    4448 
    4549    private Log log = LogFactory.getLog(getClass()); 
     
    164168                monitor.wait(); 
    165169            } 
    166             // The nameCache can be made up to date as well since everything is 
    167             // being updated 
    168             nameCacheOutOfDate = false; 
    169             nameCache = new HashMap<QName, FieldType>(fieldTypes.size()); 
     170            nameCacheOutOfDate = true; 
    170171            // One would expect that existing buckets need to be cleared first. 
    171172            // But since field types cannot be deleted we will just overwrite 
    172173            // them. 
    173174            for (FieldType fieldType : fieldTypes) { 
    174                 nameCache.put(fieldType.getName(), fieldType); 
    175175                String bucketId = AbstractSchemaCache.encodeHex(fieldType.getId().getBytes()); 
    176                 Map<SchemaId, FieldType> bucket = buckets.get(bucketId); 
    177                 if (bucket == null) { 
    178                     bucket = new ConcurrentHashMap<SchemaId, FieldType>(8, .75f, 1); 
    179                     buckets.put(bucketId, bucket); 
    180                 } 
    181                 bucket.put(fieldType.getId(), fieldType); 
     176                // Only update if it was not updated locally 
     177                // If it was updated locally either this is the refresh of that 
     178                // update, 
     179                // or the refresh for this update will follow. 
     180                if (!removeFromLocalUpdateBucket(fieldType.getId(), bucketId)) { 
     181                    Map<SchemaId, FieldType> bucket = buckets.get(bucketId); 
     182                    if (bucket == null) { 
     183                        bucket = new ConcurrentHashMap<SchemaId, FieldType>(8, .75f, 1); 
     184                        buckets.put(bucketId, bucket); 
     185                    } 
     186                    bucket.put(fieldType.getId(), fieldType); 
     187                } 
    182188            } 
    183189        } 
     
    208214            // Fill a the bucket with the new field types 
    209215            for (FieldType fieldType : fieldTypes) { 
    210                 bucket.put(fieldType.getId(), fieldType); 
     216                if (!removeFromLocalUpdateBucket(fieldType.getId(), bucketId)) { 
     217                    bucket.put(fieldType.getId(), fieldType); 
     218                } 
    211219            } 
    212220        } 
     
    236244            } 
    237245            bucket.put(id, ftToCache); 
     246            // Mark that this fieldType is updated locally 
     247            // and that the next refresh can be ignored 
     248            // since this refresh can contain an old fieldType 
     249            addToLocalUpdateBucket(id, bucketId); 
    238250        } 
    239251        // Decrement the number of buckets that are being updated again. 
    240252        decCount(); 
    241253    } 
     254 
     255    // Add the id of a field type that has been updated locally 
     256    // in a bucket. This field type will be skipped in a next 
     257    // cache refresh sequence. 
     258    // This avoids that a locally updated field type will be 
     259    // overwritten by old data by a cache refresh. 
     260    private void addToLocalUpdateBucket(SchemaId id, String bucketId) { 
     261        Set<SchemaId> localUpdateBucket = localUpdateBuckets.get(bucketId); 
     262        if (localUpdateBucket == null) { 
     263            localUpdateBucket = new HashSet<SchemaId>(); 
     264            localUpdateBuckets.put(bucketId, localUpdateBucket); 
     265        } 
     266        localUpdateBucket.add(id); 
     267    } 
     268 
     269    // Check if the field type is present in the local update bucket. 
     270    // If so, return true and remove it, in which case the refresh 
     271    // should skip it to avoid replacing the field type with old data. 
     272    private boolean removeFromLocalUpdateBucket(SchemaId id, String bucketId) { 
     273        Set<SchemaId> localUpdateBucket = localUpdateBuckets.get(bucketId); 
     274        if (localUpdateBucket == null) { 
     275            return false; 
     276        } 
     277        return localUpdateBucket.remove(id); 
     278    } 
    242279} 
  • trunk/cr/repository/test/src/test/java/org/lilyproject/repository/impl/test/SchemaCacheTest.java

    r5236 r5280  
    225225        QName ftName = new QName("testRenameFieldType", "f"); 
    226226        FieldType fieldType = typeManager.fieldTypeBuilder().name(ftName).create(); 
    227         for (int i = 0; i< 10; i++) { 
     227        for (int i = 0; i < 100; i++) { 
    228228            QName newFtName = new QName("testRenameFieldType", "f"+i); 
    229229            fieldType.setName(newFtName); 
Note: See TracChangeset for help on using the changeset viewer.