@Test public void rollbackHardTest() throws IOException, ParseException { testTableEng.put("key1", tableProvider.deserialize(testTableEng, "[1, 2, 3]")); testTableEng.put("key2", tableProvider.deserialize(testTableEng, "[4, 5, 6]")); Assert.assertEquals(2, testTableEng.commit()); testTableEng.remove("key2"); testTableEng.put("key2", tableProvider.deserialize(testTableEng, "[4, 5, 6]")); Assert.assertEquals(0, testTableEng.rollback()); testTableEng.remove("key1"); testTableEng.remove("key2"); }
@Before public void setUpTestObject() throws IOException { tableProvider = new StoreableTableProvider(sandBoxDirectory); List<Class<?>> typesTestListOne = WorkWithStoreableDataBase.createListOfTypesFromString("int int int"); List<Class<?>> typesTestListTwo = WorkWithStoreableDataBase.createListOfTypesFromString("int double boolean String"); testTableEng = tableProvider.createTable("testTable20", typesTestListOne); testTableRus = tableProvider.createTable("тестоваяТаблица21", typesTestListTwo); }
@Test public void commitHardTest() throws IOException, ParseException { testTableEng.put("key1", tableProvider.deserialize(testTableEng, "[1, 2, 3]")); testTableEng.put("key2", tableProvider.deserialize(testTableEng, "[4, 5, 6]")); Assert.assertEquals(2, testTableEng.commit()); testTableEng.put("key1", tableProvider.deserialize(testTableEng, "[7, 8, 9]")); testTableEng.put("key3", tableProvider.deserialize(testTableEng, "[10, 11, 12]")); testTableEng.remove("key2"); Assert.assertEquals(3, testTableEng.commit()); testTableEng.remove("key1"); testTableEng.remove("key3"); }
/** TEST BLOCK REMOVE TESTS */ @Test public void removeTest() throws IOException, ParseException { testTableEng.put("key", tableProvider.deserialize(testTableEng, "[1, 2, 3]")); Assert.assertNull(testTableEng.remove("nonExictingKey")); Assert.assertEquals( "[1,2,3]", tableProvider.serialize(testTableEng, testTableEng.remove("key"))); testTableRus.put( "ключ", tableProvider.deserialize(testTableRus, "[1, 2.043, true, \"Hello World!\"]")); Assert.assertNull(testTableRus.remove("несуществующийКлюч")); Assert.assertEquals( "[1,2.043,true,\"Hello World!\"]", tableProvider.serialize(testTableRus, testTableRus.remove("ключ"))); }
/** TEST BLOCK ROLLBACK TESTS */ @Test public void rollbackTest() throws IOException, ParseException { Assert.assertEquals(0, testTableEng.rollback()); for (int i = 1; i <= 5; ++i) { testTableEng.put("key" + i, tableProvider.deserialize(testTableEng, "[1, 2, 3" + i + "]")); } testTableEng.commit(); testTableEng.put("key2", tableProvider.deserialize(testTableEng, "[1, 2, 0]")); testTableEng.put("key4", tableProvider.deserialize(testTableEng, "[1, 2, 1]")); Assert.assertEquals(2, testTableEng.rollback()); Assert.assertEquals( "[1,2,32]", tableProvider.serialize(testTableEng, testTableEng.get("key2"))); Assert.assertEquals( "[1,2,34]", tableProvider.serialize(testTableEng, testTableEng.get("key4"))); for (int i = 1; i <= 5; ++i) { testTableEng.remove("key" + i); } }
/** TEST BLOCK SIZE TESTS */ @Test public void sizeTest() throws IOException, ParseException { Assert.assertEquals(0, testTableEng.size()); testTableEng.put("key1", tableProvider.deserialize(testTableEng, "[1, 2, 3]")); Assert.assertEquals(1, testTableEng.size()); testTableEng.put("key2", tableProvider.deserialize(testTableEng, "[4, 5, 6]")); testTableEng.put("key3", tableProvider.deserialize(testTableEng, "[7, 8, 9]")); Assert.assertEquals(3, testTableEng.size()); testTableEng.put("key4", tableProvider.deserialize(testTableEng, "[10, 11, 12]")); testTableEng.put("key5", tableProvider.deserialize(testTableEng, "[13, 14, 15]")); Assert.assertEquals(5, testTableEng.size()); testTableEng.commit(); Assert.assertEquals(5, testTableEng.size()); for (int i = 1; i <= 5; ++i) { testTableEng.remove("key" + i); } }
@Test(expected = IllegalArgumentException.class) public void putKeyWithWhitespaces2Test() { List<Object> valuesToPut = new ArrayList<>(); valuesToPut.add(1); valuesToPut.add(2); valuesToPut.add(3); Storeable needToPut = tableProvider.createFor(testTableEng, valuesToPut); testTableEng.put(" key ", needToPut); }
/** TEST BLOCK COMMIT TESTS */ @Test public void commitTest() throws IOException, ParseException { Assert.assertEquals(0, testTableEng.commit()); for (int i = 1; i <= 5; ++i) { testTableEng.put("key" + i, tableProvider.deserialize(testTableEng, "[1, 2, 3" + i + "]")); } Assert.assertEquals(5, testTableEng.commit()); for (int i = 1; i <= 5; ++i) { testTableEng.remove("key" + i); } }
@Test public void getRemoved() throws IOException { provider.createTable("table", types); Thread newThread = new Thread() { public void run() { try { provider.removeTable("table"); } catch (IOException e) { Assert.fail(e.getMessage()); } } }; try { newThread.start(); newThread.join(); } catch (InterruptedException e) { Assert.fail(e.getMessage()); } Assert.assertNull("error: should be no table", provider.getTable("table")); }
@Before public void setUp() throws DatabaseCorruptedException { values.add("\"string value\""); columnTypes.add(String.class); table = new TableClass(testDir, "table name", provider, columnTypes); testStoreableValue = new StoreableClass(table, values); testDir.toFile().mkdir(); correctKey1 = new String(new byte[] {folderIndex + fileIndex * 16, 'k', 'e', 'y', '1'}); correctKey2 = new String(new byte[] {folderIndex + fileIndex * 16, 'k', 'e', 'y', '2'}); // Wrong key will contain changed first byte. wrongKey = new String(new byte[] {'w', 'r', 'o', 'n', 'g'}); testStringValue = provider.serialize(table, testStoreableValue); }
private void update() throws DatabaseCorruptedException, IOException { try (RandomAccessFile file = new RandomAccessFile(filePath.toString(), "r")) { if (file.length() == 0) { throw new DatabaseCorruptedException("Data base corrupted: empty file found"); } List<String> keys = new LinkedList<>(); List<Integer> offsets = new LinkedList<>(); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); byte b; int counter = 0; do { // Read keys. while ((b = file.readByte()) != 0) { counter++; bytes.write(b); } ++counter; offsets.add(file.readInt()); counter += 4; String key = bytes.toString(TableManager.CODE_FORMAT); bytes.reset(); if (!checkKey(key)) { throw new DatabaseCorruptedException("Wrong key found in file " + filePath.toString()); } keys.add(key); } while (counter < offsets.get(0)); offsets.add((int) file.length()); offsets.remove(0); // It's current position in file, we don't need it in list. Iterator<String> keyIterator = keys.iterator(); for (int nextOffset : offsets) { // Read values. while (counter < nextOffset) { bytes.write(file.readByte()); counter++; } if (bytes.size() > 0) { try { fileMap.put( keyIterator.next(), provider.deserialize(table, bytes.toString(TableManager.CODE_FORMAT))); } catch (ParseException e) { throw new RuntimeException( "Data corrupted in file " + filePath.toString() + " : " + e.getMessage()); } bytes.reset(); } else { throw new DatabaseCorruptedException("Data corrupted in file " + filePath.toString()); } } bytes.close(); } }
/** TEST BLOCK PUT TESTS */ @Test public void putTest() throws IOException, ParseException { Assert.assertNull( testTableEng.put("key", tableProvider.deserialize(testTableEng, "[1, 2, 3]"))); Assert.assertEquals( "[1,2,3]", tableProvider.serialize( testTableEng, testTableEng.put("key", tableProvider.deserialize(testTableEng, "[1, 2, 3]")))); Assert.assertEquals( "[1,2,3]", tableProvider.serialize( testTableEng, testTableEng.put("key", tableProvider.deserialize(testTableEng, "[-1, -2, -3]")))); testTableEng.remove("key"); Assert.assertNull( testTableRus.put( "ключ", tableProvider.deserialize(testTableRus, "[1, 2.043, true, \"Hello World!\"]"))); Assert.assertEquals( "[1,2.043,true,\"Hello World!\"]", tableProvider.serialize( testTableRus, testTableRus.put( "ключ", tableProvider.deserialize(testTableRus, "[1, 2.043, true, \"Hello World!\"]")))); Assert.assertEquals( "[1,2.043,true,\"Hello World!\"]", tableProvider.serialize( testTableRus, testTableRus.put( "ключ", tableProvider.deserialize( testTableRus, "[-1, -2.043, false, \"Bye Bye World!\"]")))); testTableRus.remove("ключ"); }
@Test public void getCreated() throws IOException { Thread newThread = new Thread() { public void run() { try { table = provider.createTable("table", types); } catch (IOException e) { Assert.fail(e.getMessage()); } } }; try { newThread.start(); newThread.join(); } catch (InterruptedException e) { Assert.fail(e.getMessage()); } Assert.assertSame("error: should get table", provider.getTable("table"), table); }
/** * Выполняет фиксацию изменений. * * @return Число записанных изменений. * @throws java.io.IOException если произошла ошибка ввода/вывода. Целостность таблицы не * гарантируется. */ @Override public int commit() throws IOException { int numberOfCommittedChanges = uncommittedChanges(); Set<Map.Entry<String, Storeable>> dbSet = tableIndexedData.entrySet(); for (int nDir = 0; nDir < 16; ++nDir) { for (int nFile = 0; nFile < 16; ++nFile) { if (tableFileModified[nDir][nFile]) { if (tableFiles[nDir][nFile] == null) { File subDir = new File(tableRootDir, Integer.toString(nDir) + ".dir"); File subFile = new File(subDir, Integer.toString(nFile) + ".dat"); if (!subDir.exists()) { if (!subDir.mkdir()) { throw new IllegalStateException("Sub dir was not created"); } } tableFiles[nDir][nFile] = new TableFile(subFile); } List<TableFile.Entry> fileData = new ArrayList<>(); Iterator<Map.Entry<String, Storeable>> iter = dbSet.iterator(); while (iter.hasNext()) { Map.Entry<String, Storeable> tempMapEntry = iter.next(); HashcodeDestination dest = new HashcodeDestination(tempMapEntry.getKey()); if (dest.getDir() == nDir && dest.getFile() == nFile) { fileData.add( new TableFile.Entry( tempMapEntry.getKey(), tableProvider.serialize(this, tempMapEntry.getValue()))); } } tableFiles[nDir][nFile].writeEntries(fileData); tableFileModified[nDir][nFile] = false; } } } tableOnDisk.clear(); tableOnDisk.putAll(tableIndexedData); return numberOfCommittedChanges; }
protected void commit() throws IOException { if (fileMap.size() == 0) { filePath.toFile().delete(); filePath.getParent().toFile().delete(); } else { filePath.getParent().toFile().mkdir(); try (RandomAccessFile file = new RandomAccessFile(filePath.toString(), "rw")) { file.setLength(0); Set<String> keys = fileMap.keySet(); List<Integer> reserved = new LinkedList<>(); List<Integer> offsets = new LinkedList<>(); for (String currentKey : keys) { file.write(currentKey.getBytes(TableManager.CODE_FORMAT)); file.write('\0'); reserved.add((int) file.getFilePointer()); file.writeInt(0); // Place reserved for offset. } for (String currentKey : keys) { // Write values. offsets.add((int) file.getFilePointer()); file.write( provider .serialize(table, fileMap.get(currentKey)) .getBytes(TableManager.CODE_FORMAT)); } Iterator<Integer> offsetIterator = offsets.iterator(); for (int offsetPos : reserved) { // Write offsets in reserved places. file.seek(offsetPos); file.writeInt(offsetIterator.next()); } } catch (FileNotFoundException e) { throw new IOException("File not found: " + filePath.toString()); } catch (UnsupportedEncodingException e) { throw new IOException("Can't encode file: " + filePath.toString()); } } }
@Test(expected = IllegalArgumentException.class) public void putNullKeyTest() throws IOException, ParseException { testTableEng.put( null, testTableEng.put("key", tableProvider.deserialize(testTableEng, "[1, 2, 3]"))); }
private void index() { File[] subDirsList = tableRootDir.listFiles(); if (subDirsList != null) { for (File subDir : subDirsList) { int numberOfSubDir; if (subDir.getName().equals(SignatureFile.signatureFileName)) { continue; } if (!subDir.isDirectory()) { throw new IllegalStateException("In table root dir found object is not a directory"); } String[] tableSubDirName = subDir.getName().split("[.]"); try { numberOfSubDir = Integer.parseInt(tableSubDirName[0]); } catch (NumberFormatException e) { throw new IllegalStateException("Table root directory contains not 0.dir ... 15.dir"); } if (numberOfSubDir < 0 || numberOfSubDir > 15 || !tableSubDirName[1].equals("dir") || tableSubDirName.length != 2) { throw new IllegalStateException("Table root directory contains not 0.dir ... 15.dir"); } File[] subFilesList = subDir.listFiles(); if (subFilesList != null && subFilesList.length == 0) { throw new IllegalStateException("data base contains empty dir"); } if (subFilesList != null) { for (File subFile : subFilesList) { int numberOfSubFile; if (!subFile.isFile()) { throw new IllegalStateException("In table sub dir found object is not a file"); } String[] dbFileName = subFile.getName().split("[.]"); try { numberOfSubFile = Integer.parseInt(dbFileName[0]); } catch (NumberFormatException e) { throw new IllegalStateException("Table sub directory contains not 0.dat ... 15.dat"); } if (numberOfSubFile < 0 || numberOfSubFile > 15 || !dbFileName[1].equals("dat") || dbFileName.length != 2) { throw new IllegalStateException("Table sub directory contains not 0.dat ... 15.dat"); } else if (subFile.length() == 0) { throw new IllegalStateException("Empty file in sub dir"); } else { tableFiles[numberOfSubDir][numberOfSubFile] = new TableFile(subFile); List<TableFile.Entry> fileData = tableFiles[numberOfSubDir][numberOfSubFile].readEntries(); for (TableFile.Entry i : fileData) { HashcodeDestination dest = new HashcodeDestination(i.getKey()); if (dest.getFile() != numberOfSubFile || dest.getDir() != numberOfSubDir) { throw new IllegalStateException("Wrong key placement"); } try { tableIndexedData.put(i.getKey(), tableProvider.deserialize(this, i.getValue())); } catch (ParseException e) { throw new IllegalStateException("Can't deserialize", e); } } } } } } } tableOnDisk = new HashMap<>(tableIndexedData); }
@After public void tearDownTestObject() throws IOException { tableProvider.removeTable("testTable20"); tableProvider.removeTable("тестоваяТаблица21"); DeleteDirectory.rm(sandBoxDirectory); }