Skip to content

Commit

Permalink
Uploading to GitHub
Browse files Browse the repository at this point in the history
  • Loading branch information
nofatclips committed Jun 16, 2013
0 parents commit 79857b1
Show file tree
Hide file tree
Showing 7 changed files with 440 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/com/nofatclips/thumbtack/ThumbTackDB.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.nofatclips.thumbtack;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

import com.nofatclips.thumbtack.db.DataBase;
import com.nofatclips.thumbtack.db.InvalidRollbackException;

public class ThumbTackDB {

private DataBase DB;

public ThumbTackDB() {
this.DB = new DataBase();
}

public static void main(String[] args) {
ThumbTackDB instance = new ThumbTackDB();
try {
instance.repl();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public void repl() throws IOException {
String s;
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
boolean keepRunning = true;
while (keepRunning) {
s = stdin.readLine();
if (s == null || s.length() == 0) continue;
String[] items = s.split(" ");
String command = items[0];
List<String> arguments = Arrays.asList(items).subList(1, items.length);
try {
keepRunning = execute(command, arguments);
} catch (IndexOutOfBoundsException e){
System.out.println("INVALID ARGUMENTS FOR " + command);
}
}

}

// TODO Refactor this using Command pattern
private boolean execute(String command, List<String> arguments) throws IndexOutOfBoundsException {
command = command.toUpperCase();
if (command.equals("SET")) {
this.DB.set(arguments.get(0), arguments.get(1));
} else if (command.equals("GET")) {
String s = this.DB.get(arguments.get(0));
System.out.println((s == null) ? "NULL" : s);
} else if (command.equals("UNSET")) {
this.DB.unset(arguments.get(0));
} else if (command.equals("NUMEQUALTO") || command.equals("NET")) {
System.out.println(this.DB.numEqualTo(arguments.get(0)));;
} else if (command.equals("BEGIN")) {
this.DB.begin();
} else if (command.equals("ROLLBACK")) {
try {
this.DB.rollback();
} catch (InvalidRollbackException e) {
System.out.println("INVALID ROLLBACK");
}
} else if (command.equals("COMMIT")) {
this.DB.commit();
} else if (command.equals("END")) {
return false;
} else {
System.out.println("INVALID COMMAND");
}
return true;
}

}
74 changes: 74 additions & 0 deletions src/com/nofatclips/thumbtack/db/BaseDataLayer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.nofatclips.thumbtack.db;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
*
* The base layer for the DB. Implementation should be straightforward.
*
* It has an inverted (value to key) index for fast (<O(n)) implementation of numEqualTo()
*
* @author DeK
*
*/

public class BaseDataLayer implements DataLayer {

private Map<String, String> layerStore;
private BucketCounter layerIndex;

public BaseDataLayer() {
this.layerStore = new HashMap<String, String>();
this.layerIndex = new BucketCounter();
}

@Override
public void set(String name, String value) {
index().removeOne(get(name)); // Remove old value from index if exists
store().put(name, value);
index().putOne(value);
}

@Override
public String get(String name) {
return store().get(name);
}

@Override
public void unset(String name) {
index().removeOne(get(name));
store().remove(name);
}

@Override
public int numEqualTo(String value) {
return index().numEqualTo(value);
}

public boolean containsValue(String value) {
return index().containsKey(value);
}

public void mergeFrom(IncrementalDataLayer that) {
this.store().putAll(that.store());
this.unsetAll(that.deletedKeys);
this.index().mergeMap(that.index());
}

protected void unsetAll(Set<String> deletedKeys) {
for (String deletedKey: deletedKeys) {
unset(deletedKey);
}
}

public BucketCounter index() {
return this.layerIndex;
}

public Map<String, String> store() {
return this.layerStore;
}

}
70 changes: 70 additions & 0 deletions src/com/nofatclips/thumbtack/db/BucketCounter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.nofatclips.thumbtack.db;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class BucketCounter {

private Map<String, Integer> index;

public BucketCounter() {
this.index = new HashMap<String, Integer>();
}

public Integer get(String value) {
return this.index.get(value);
}

public boolean containsKey(String value) {
return this.index.containsKey(value);
}

public void putOne(String value) {
if (!containsKey(value)) {
initKey(value);
}
this.index.put(value, get(value)+1);
}

public void mergeMap(BucketCounter that) {
for (Map.Entry<String, Integer> entry : that.entrySet()) {
initKey(entry.getKey(), entry.getValue());
}
}

private Set<Map.Entry<String, Integer>> entrySet() {
return this.index.entrySet();
}

public void initKey(String value, Integer count) {
this.index.put(value, count);
}

public void initKey(String value) {
initKey(value, 0);
}

public void removeOne(String value) {
if (containsKey(value)) {
this.index.put(value, get(value)-1);
}
}

public int numEqualTo(String value) {
Integer bucketSize = this.index.get(value);
if (bucketSize == null) return 0;
return bucketSize;
}

public String toString() {
String ret = "{";
String sep = "";
for (Map.Entry<String, Integer> entry : entrySet()) {
ret += sep + entry.getKey() + ": '" + entry.getValue() + "'";
sep = ", ";
}
return ret + "}";
}

}
91 changes: 91 additions & 0 deletions src/com/nofatclips/thumbtack/db/DataBase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.nofatclips.thumbtack.db;

import java.util.ArrayDeque;
import java.util.Deque;

/**
*
* Classic composite pattern. It has a stack rather than a list of items and
* the head is stored separately. It mostly delegates every operation
* to the current item (the one on top of the stack, or the head if
* the stack is empty).
*
* Each item provides incremental information to be added to the head
* on commit.
*
* @author DeK
*
*/

public class DataBase implements DataLayer {

private BaseDataLayer baseLayer;
private Deque<IncrementalDataLayer> layerStack;

public DataBase() {
this.baseLayer = new BaseDataLayer();
this.layerStack = new ArrayDeque<IncrementalDataLayer>();
}

@Override
public void set(String name, String value) {
currentLayer().set(name, value);
}

@Override
public String get(String name) {
// Iterator<DataLayer> inStackingOrder = this.layerStack.descendingIterator();
// while(inStackingOrder.hasNext()){
// String ret = inStackingOrder.next().get(name);
// if (ret != null) return ret;
// }
return currentLayer().get(name);
}

@Override
public void unset(String name) {
currentLayer().unset(name);
}

@Override
public int numEqualTo(String value) {
return currentLayer().numEqualTo(value);
}

public void begin() {
// Creates a new layer, uses the current one as its underlying layer, pushes onto stack
push(new IncrementalDataLayer(currentLayer()));
}

public void rollback() throws InvalidRollbackException {
if (transactionRunning()) {
pop();
} else {
throw new InvalidRollbackException();
}
}

protected boolean transactionRunning() {
return !this.layerStack.isEmpty();
}

public void commit() {
while (transactionRunning()) {
pop().mergeBack();
}
}

public BaseDataLayer currentLayer() {
if (transactionRunning()) return this.layerStack.peekFirst();
return this.baseLayer;
}

public IncrementalDataLayer pop() {
return this.layerStack.pop();
}

public void push(IncrementalDataLayer newLayer) {
this.layerStack.push(newLayer);
}

}
10 changes: 10 additions & 0 deletions src/com/nofatclips/thumbtack/db/DataLayer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.nofatclips.thumbtack.db;

public interface DataLayer {

public void set(String name, String value);
public String get(String name);
public void unset(String name);
public int numEqualTo(String value);

}
Loading

0 comments on commit 79857b1

Please sign in to comment.