001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.core.storage.sql; 020 021import java.io.Serializable; 022import java.util.HashSet; 023import java.util.Set; 024 025/** 026 * A set of invalidations. 027 * <p> 028 * Records both modified and deleted fragments, as well as "parents modified" fragments. 029 */ 030public class Invalidations implements Serializable { 031 032 private static final long serialVersionUID = 1L; 033 034 /** Pseudo-table for children invalidation. */ 035 public static final String PARENT = "__PARENT__"; 036 037 /** Pseudo-table for series proxies invalidation. */ 038 public static final String SERIES_PROXIES = "__SERIES_PROXIES__"; 039 040 /** Pseudo-table for target proxies invalidation. */ 041 public static final String TARGET_PROXIES = "__TARGET_PROXIES__"; 042 043 public static final int MODIFIED = 1; 044 045 public static final int DELETED = 2; 046 047 /** 048 * Maximum number of invalidations kept, after which only {@link #all} is set. This avoids accumulating too many 049 * invalidations in memory, at the expense of more coarse-grained invalidations. 050 */ 051 public static final int MAX_SIZE = 10000; 052 053 /** 054 * Used locally when invalidating everything, or when too many invalidations have been received. 055 */ 056 public boolean all; 057 058 /** null when empty */ 059 public Set<RowId> modified; 060 061 /** null when empty */ 062 public Set<RowId> deleted; 063 064 public Invalidations() { 065 } 066 067 public Invalidations(boolean all) { 068 this.all = all; 069 } 070 071 public boolean isEmpty() { 072 return modified == null && deleted == null && !all; 073 } 074 075 public void clear() { 076 all = false; 077 modified = null; 078 deleted = null; 079 } 080 081 protected void setAll() { 082 all = true; 083 modified = null; 084 deleted = null; 085 } 086 087 protected void checkMaxSize() { 088 if (modified != null && modified.size() > MAX_SIZE // 089 || deleted != null && deleted.size() > MAX_SIZE) { 090 setAll(); 091 } 092 } 093 094 /** only call this if it's to add at least one element in the set */ 095 public Set<RowId> getKindSet(int kind) { 096 switch (kind) { 097 case MODIFIED: 098 if (modified == null) { 099 modified = new HashSet<RowId>(); 100 } 101 return modified; 102 case DELETED: 103 if (deleted == null) { 104 deleted = new HashSet<RowId>(); 105 } 106 return deleted; 107 } 108 throw new AssertionError(); 109 } 110 111 public void add(Invalidations other) { 112 if (other == null) { 113 return; 114 } 115 if (all) { 116 return; 117 } 118 if (other.all) { 119 setAll(); 120 return; 121 } 122 if (other.modified != null) { 123 if (modified == null) { 124 modified = new HashSet<RowId>(); 125 } 126 modified.addAll(other.modified); 127 } 128 if (other.deleted != null) { 129 if (deleted == null) { 130 deleted = new HashSet<RowId>(); 131 } 132 deleted.addAll(other.deleted); 133 } 134 checkMaxSize(); 135 } 136 137 public void addModified(RowId rowId) { 138 if (all) { 139 return; 140 } 141 if (modified == null) { 142 modified = new HashSet<RowId>(); 143 } 144 modified.add(rowId); 145 checkMaxSize(); 146 } 147 148 public void addDeleted(RowId rowId) { 149 if (all) { 150 return; 151 } 152 if (deleted == null) { 153 deleted = new HashSet<RowId>(); 154 } 155 deleted.add(rowId); 156 checkMaxSize(); 157 } 158 159 public void add(Serializable id, String[] tableNames, int kind) { 160 if (tableNames.length == 0) { 161 return; 162 } 163 Set<RowId> set = getKindSet(kind); 164 for (String tableName : tableNames) { 165 set.add(new RowId(tableName, id)); 166 } 167 checkMaxSize(); 168 } 169 170 @Override 171 public String toString() { 172 StringBuilder sb = new StringBuilder(this.getClass().getSimpleName() + '('); 173 if (all) { 174 sb.append("all=true"); 175 } 176 if (modified != null) { 177 sb.append("modified="); 178 sb.append(modified); 179 if (deleted != null) { 180 sb.append(','); 181 } 182 } 183 if (deleted != null) { 184 sb.append("deleted="); 185 sb.append(deleted); 186 } 187 sb.append(')'); 188 return sb.toString(); 189 } 190 191}