@Override
	public void add(Address addr, T value) {
		lock.acquire();
		try {
			checkDeleted();
			if (!saveableObjectClass.isAssignableFrom(value.getClass())) {
				throw new IllegalArgumentException("value is not " + saveableObjectClass.getName());
			}
			long addrKey = addrMap.getKey(addr, true);

			T oldValue = null;
			if (propertyTable != null) {
				oldValue = cache.get(addrKey);
				if (oldValue == null) {
					oldValue = valueReader.apply(addrKey);
				}
			}

			String tableName = getTableName();
			Schema s;
			DBRecord rec;
			if (saveableObjectClass != GenericSaveable.class) {
				ObjectStorageAdapterDB objStorage = new ObjectStorageAdapterDB();
				value.save(objStorage);
				s = objStorage.getSchema(value.getSchemaVersion());
				checkSchema(s);
				createPropertyTable(tableName, s);
				rec = schema.createRecord(addrKey);
				objStorage.save(rec);
			}
			else { // GenericSaveable
				GenericSaveable genericSaveable = ((GenericSaveable) value);
				DBRecord originalRec = genericSaveable.record;
				s = genericSaveable.schema;
				checkSchema(s);
				createPropertyTable(tableName, s);
				rec = originalRec.copy();
				rec.setKey(addrKey);
			}

			propertyTable.putRecord(rec);
			cache.put(addrKey, value);

			if (!isPrivate(value)) {
				changeMgr.setPropertyChanged(name, addr, oldValue, value);
			}
		}
		catch (IOException e) {
			errHandler.dbError(e);
		}
		finally {
			lock.release();
		}

	}
Attempt to upgrade the map table records to the current schema.
If unable to upgrade any of the map records, the table is removed.
@param tokenInstance token saveable instance
@param monitor task monitor
@return true if all records were successfully upgrade.  A false
value indicates that one or more entries were dropped.
@throws CancelledException if task is cancelled
@throws IOException if IO error occurs
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/properties/ObjectPropertyMapDB.java