Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Много-файловое хранилище Java объектов в формате xml

Anna | 5.06.2014 | нет комментариев

В программировании Зачастую перед нами встают задачи, которые мы можем решить несколькими путями: обнаружить и применять теснее готовые решения, либо же решать задачу самосильно. Хоть и написано уйма спецификаций и их реализаций, они не неизменно дают нам то, что требуется в определенном случае. Вот и мне в следующий раз пришлось столкнуться с сходственной обстановкой.
Задача состояла в хранении объектов в файле в формате xml. Ничего казалось бы трудного, если бы не несколько «но». Объектов много, имеют они древовидную конструкцию и над ними непрерывно выполняются операции добавления, метаморфозы и удаления в различных потоках. Как вы понимаете непрерывные запись и чтение большого xml файла достаточно трудоемкая задача. Тем больше если с одними и теми же данными работают несколько потоков. Так собственно и родилась идея написать много-файловое хранилище объектов в формате xml.
В этой статье я не буду рассматривать саму реализацию. Приведу лишь основные идеи и как применять эту реализацию. Если вы хотите углубиться, то можете скачать посмотреть начальные коды.

Исходники доступны по ссылке: xdstore-1.3
Начальные тексты немножко отличаются от приведенных в этой статье. В них были глубже проработаны исключительные обстановки, а именно, — для всякой операции, включая чтение, выбрасывается свое исключение. Также в последней версии реализована фрагментация.

Основная идея разработки

Основная идея заключается в том, Дабы объекты беречь не в одном файле, а в некотором множестве. При этом предоставить вероятность настраивать политики хранения для всякого требуемого класса. Для класса дозволено установить одну из следующих политик:

  • ParentObjectFile – объекты класса будут сохраняться в файле объекта обладателя как дочерние элементы, эта политика используется по умолчанию;
  • SingleObjectFile – всем объекту класса предоставляется обособленный файл, а в файле объекта обладателя будет сохранена лишь ссылка на данный объект (в последующем буду легко называть ее объектной ссылкой); все файлы всякого объекта будут сохраняться в отдельной папке внутри хранилища;
  • ClassObjectsFile – все объекты этого класса будут храниться в отдельном файле, а в файлах объектов обладателей будут сохранены лишь объектные ссылки.

Под представлением объектной ссылки воспринимается объект указанного класса, у которого проставлено одно поле – идентификатор. В xml файле взамен полных данных этого объекта сохраняется лишь имя класса и идентификатор, Дабы в последующем по этой ссылке дозволено было получить все данные. Загрузка таких объектов подобна поздней инициализации в hibernate.
Сберегаемые объекты обязаны быть реализованы как JavaBeans с способами get(is) и set для сберегаемых полей.

Одна увлекательная задача

Дабы отменнее осознать обстановку, в которую мы попадаем при попытке реализовать такое хранилище, нужно верно поставить задачу. В терминах БД звучит она дальнейшим образом: в таблице базы данных имеются две строки, единовременно начинаются две транзакции, всякая из которых модифицирует обе строки, после этого завершается коммитом первая транзакция и начинается третья, которая также модифицирует эти две строки.
Нас волнует поведение в сходственной обстановки, т.е. что произойдет с данными в всякой из транзакций. В нынешней реализации библиотеки поведение будет дальнейшим:
1) От того что данные были модифицированы первой транзакцией, то вторая транзакция получит отказ на метаморфоза данных в виде исключения. Объясняется это тем, что первая и вторая транзакции начались в одно время и скорее каждого трудились с идентичными копиями, и Дабы не утратить метаморфозы первой транзакции 2-й нужно отказать.
2) А вот данные третьей транзакции будут приняты, от того что она началась позже коммита первой транзакции и работает с обновленными данными.
От того что это достаточно простая реализация, то при решении поставленной задачи не применялись блокировки записей Дабы избежать deadlock-ов и необходимости отката транзакций по таймауту. В этом случае выбрасывается исключение, по которому транзакция должна быть откачена.

Предисловие применения

Сама цель данной разработки получить примитивную и эластичную библиотеку, разрешающую сберегать объекты в формате xml. Следственнополучившийся интерфейс достаточно примитивен, а требования предъявляемые к сберегаемым объектам сведены к минимуму. Основное требование для всякого сберегаемого объекта заключается в необходимости реализовать примитивный интерфейс IXmlDataStoreIdentifiable. Выглядит он дальнейшим образом:

public interface IXmlDataStoreIdentifiable {

	String	getId();

	void	setId(String id);

}

Как вы можете видеть, нужно лишь реализовать два способа работы с идентификатором объекта. Это нужное условие обусловлено тем, что при некоторых политиках сохраняются лишь ссылки на объекты, по которым в последующем может понадобиться восстановить (загрузить) все свойства. Ссылка в xml файле выглядит дальнейшим образом:

<reference id="cc74e3f2"/>

При загрузке этой ссылки будет сделан объект указанного класса и у него проставлено качество идентификатора. Остальные поля будут проинициализированы по умолчанию, т. е. они не будут загружены.
Разглядим сейчас примитивный пример настройки хранилища для хранения объектов следующих классов: XdUniverse и XdGalaxy. Для начала определим их классы.

package org.flib.xdstore.entities;

import java.util.Collection;
import org.flib.xdstore.IXmlDataStoreIdentifiable;

public class XdUniverse implements IXmlDataStoreIdentifiable {

	private String	id;

	private Collection<XdGalaxy>	galaxies;

	@Override
	public String getId() {
		return id;
	}

	@Override
	public void setId(final String id) {
		this.id = id;
	}

	public Collection<XdGalaxy> getGalaxies() {
		return galaxies;
	}

	public void setGalaxies(Collection<XdGalaxy> galaxies) {
		this.galaxies = galaxies;
	}

	public void addGalaxy(XdGalaxy galaxy) {
		galaxies.add(galaxy);
	}

        public XdGalaxy removeGalaxy() {
		final Iterator<XdGalaxy> it = galaxies.iterator();
		XdGalaxy galaxy = null;
		if(it.hasNext()) {
			galaxy = it.next();
			it.remove();
		}
		return galaxy;
	}
}

И простенький класс XdGalaxy.

package org.flib.xdstore.entities;

import org.flib.xdstore.IXmlDataStoreIdentifiable;

public class XdGalaxy implements IXmlDataStoreIdentifiable {

	private String id;

	@Override
	public String getId() {
		return id;
	}

	@Override
	public void setId(String id) {
		this.id = id;
	}
}

Сейчас дозволено разглядеть настройку хранилища для указанных сущностей.

final XmlDataStore store = new XmlDataStore("./teststore");
store.setStorePolicy(XdUniverse.class, XmlDataStorePolicy.ClassObjectsFile);
store.setStorePolicy(XdGalaxy.class, XmlDataStorePolicy.ClassObjectsFile);

Теперь мы предпочли настройки, что все объекты всякого из классов будут храниться в своем файле, т.е. для всякого класса один файл. Дозволено применять другие настройки и, скажем, не указывать политику для класса XdGalaxy, — тогда его объекты будут сохраняться совместно с объектами класса XdUniverse.
В итоге для наших настроек позже записи объектов мы получим два файла: XdUniverse.xml и XdGalaxy.xml.

<?xml version="1.0" encoding="UTF-8"?>
<objects>
	<object isNull="false" id="002df141">
		<collection name="Galaxies">
			<reference id="cc74e3f2"/>
			<reference id="ca519d20"/>
		</collection>
		<object name="Id" isNull="false" value="002df141"/>
	</object> 
</objects>

Как видно из примера в этом файле хранятся ссылки на объекты из второго файла XdGalaxy.xml, приведенного ниже.

<?xml version="1.0" encoding="UTF-8"?>
<objects>
	<object isNull="false" id="cc74e3f2">
		<object name="Id" isNull="false" value="cc74e3f2"/>
	</object>
	<object isNull="false" id="ca519d20">
		<object name="Id" isNull="false" value="ca519d20"/>
	</object> 
</objects>

Таким образом мы получили 2-х файловое хранилище для наших объектов. Если нам не требуются объекты класса XdGalaxy, то мы можем загрузить лишь объекты класса XdUniverse и работpermark! public <T extends IXmlDataStoreIdentifiable> boolean updateObject(final T object) throws XmlDataStoreException public <T extends IXmlDataStoreIdentifiable> boolean deleteObject(final T reference) throws XmlDataStoreException public <T extends IXmlDataStoreIdentifiable> boolean deleteObjects(final Collection<T> references) throws XmlDataStoreException }
Следует подметить, что все зависимые объекты, которые хранятся в отдельных от обладателя файлах, обязаны быть очевидно обновлены либо удалены. Скажем, в нашем случае при удалении объекта класса XdGalaxy из объекта XdUniverse нужно обновить объект XdUniverse и добавочно очевидно удалить XdGalaxy.

final XmlDataStore store = initStore("./teststore");
final XmlDataStoreTransaction tx = store.beginTransaction();
try {
	final Map<String, XdUniverse> roots = store.loadRoots(XdUniverse.class);
	for (final XdUniverse root : roots.values()) {
		final Collection<XdGalaxy> galaxies = root.getGalaxies();
		store.loadObjects(galaxies);
	}

	if(roots.size() > 0) {
		final XdUniverse universe = roots.values().iterator().next();
		final XdGalaxy galaxy = universe.removeGalaxy();
		if(galaxy != null) {
			store.updateRoot(universe);
			store.deleteObject(galaxy);
		}
	}

	tx.commit();
} catch(XmlDataStoreException e) {
	tx.rollback();
}

В случае добавления объекта код выглядит дальнейшим образом.

final XmlDataStore store = initStore("./teststore");
final XmlDataStoreTransaction tx = store.beginTransaction();
try {
	final Map<String, XdUniverse> roots = store.loadRoots(XdUniverse.class);
	for (final XdUniverse root : roots.values()) {
		final Collection<XdGalaxy> galaxies = root.getGalaxies();
		store.loadObjects(galaxies);
	}

	if(roots.size() > 0) {
		final XdUniverse universe = roots.values().iterator().next();
		final XdGalaxy galaxy = initGalaxy();	// initialization XdGalaxy

		universe.addGalaxy(galaxy);

		store.updateRoot(universe);
		store.saveObject(galaxy);
	}

	tx.commit();
} catch(XmlDataStoreException e) {
	tx.rollback();
}

Если же политика сохранения ParentObjectFile, то для дочерних объектов нет необходимости очевидно исполнять операции удаления и сохранения, от того что позже обновления объекта обладателя нужная операция будет исполнена механически.
Полная чистка нашего хранилища будет выглядеть дальнейшим образом:

final XmlDataStore store = initStore(storedir);
final XmlDataStoreTransaction tx = store.beginTransaction();
try {
final Map<String, XdUniverse> roots = store.loadRoots(XdUniverse.class);
	for (final XdUniverse root : roots.values()) {
		final Collection<XdGalaxy> galaxies = root.getGalaxies();

		store.deleteObjects(galaxies);
		store.deleteRoot(root);
	}
	tx.commit();
} catch(XmlDataStoreException e) {
	tx.rollback();
}

Из примера видно, что нам даже не понадобилось загружать объекты класса XdGalaxy перед удалением. Мы легко передали коллекцию объектных ссылок. Это допустимо от того что объектная ссылка хранит идентификатор объекта.

Немножко о реализации

Для возрастания продуктивности работы хранилища применяется неотключаемое кэширование. Т.е. при работе с любым ресурсным объектом (файлом) все хранимые в нем объекты загружаются и кэшируются при первой транзакции. Все остальные транзакции работают с теснее кэшированными данными. Данные кэша сбрасываются, когда завершается последняя транзакция, которая работает с этим ресурсным объектом. Все метаморфозы регистрируются в кэше и не сбрасываются на диск до тех пор, пока не происходит принятие транзакции.
От того что в ходе выполнения транзакции может быть затронуто неопределенное число ресурсных объектов, то операция принятия изменений транзакции выполняется над всеми поочередно. Если при этом процессе происходит какая-либо оплошность, то целостность хранилища данных нарушается и выбрасывается исключение типа XmlDataStoreRuntimeException. В нынешней реализации поправление целостного состояния хранилища не реализовано. Это один из значительных недостатков нынешней версии.

Планы по становлению

В нынешней реализации при большом числе объектов определенного класса и политике хранения ClassObjectsFile, трудоемкость операций чтения и записи растет прямо пропорционально росту числа объектов. Для того Дабы повысить эффективность хранилища планируется реализовать фрагментацию и построение файла индекса. Фрагментация подразумевает под собой разбиение одного файла на фрагменты, содержащие ограниченное число объектов, а индекс в данном случае будет содержать ссылки с указанием файла фрагмента, в котором сохранен объект.
Также в планы входит реализация поправления целостного состояния хранилища позже сбоя при принятии изменений транзакции.

Источник: programmingmaster.ru

Оставить комментарий
БАЗА ЗНАНИЙ
СЛУЧАЙНАЯ СТАТЬЯ
СЛУЧАЙНЫЙ БЛОГ
СЛУЧАЙНЫЙ МОД
СЛУЧАЙНЫЙ СКИН
НОВЫЕ МОДЫ
НОВЫЕ СКИНЫ
НАКОПЛЕННЫЙ ОПЫТ
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB