├── .idea ├── .gitignore ├── vcs.xml ├── projects.iml ├── libraries │ ├── Maven__junit_junit_4_13.xml │ ├── Maven__com_google_inject_guice_4_0.xml │ ├── Maven__aopalliance_aopalliance_1_0.xml │ ├── Maven__com_google_guava_guava_16_0_1.xml │ ├── Maven__javax_inject_javax_inject_1.xml │ └── Maven__org_hamcrest_hamcrest_core_1_3.xml ├── modules.xml ├── misc.xml ├── jarRepositories.xml ├── compiler.xml └── uiDesigner.xml ├── README.md ├── talks.png ├── Code Review.pdf ├── Dependency Injection.pdf ├── Git Internals Script.pdf ├── java-projects ├── src │ ├── main │ │ ├── resources │ │ │ └── logging.properties │ │ └── java │ │ │ ├── logger │ │ │ ├── Timer.java │ │ │ ├── Logger.java │ │ │ ├── SugaredLogger.java │ │ │ ├── FastLogger.java │ │ │ ├── LogClientImpl.java │ │ │ └── LogClient.java │ │ │ ├── exceptions │ │ │ └── LoggingException.java │ │ │ ├── modules │ │ │ ├── PropertiesModule.java │ │ │ └── LoggingModule.java │ │ │ ├── Main.java │ │ │ └── TaskManager.java │ └── test │ │ └── java │ │ ├── TestTimer.java │ │ └── LoggerTest.java ├── output.txt ├── pom.xml └── java-projects.iml ├── system design contest ├── AmarNath-SystemDesign-Hotstar.pdf ├── Mihir - LiveBroadcastService.pdf ├── Vasant - Hotstar System design.pdf ├── Guillaume - System design - ESPN.pdf ├── Vasavi - Live video broadcasting system-1.docx └── Mincy - Live_video_Streaming_-_sys_design-1.pdf ├── git_commands.txt └── Transformer.go /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # projects 2 | These are project resources for the live YouTube lectures. 3 | -------------------------------------------------------------------------------- /talks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/talks.png -------------------------------------------------------------------------------- /Code Review.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/Code Review.pdf -------------------------------------------------------------------------------- /Dependency Injection.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/Dependency Injection.pdf -------------------------------------------------------------------------------- /Git Internals Script.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/Git Internals Script.pdf -------------------------------------------------------------------------------- /java-projects/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | logger.fast.identifier=service-log: 2 | logger.fast.buffer.size=5000 3 | output-file.name=java-projects/output.txt -------------------------------------------------------------------------------- /system design contest/AmarNath-SystemDesign-Hotstar.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/system design contest/AmarNath-SystemDesign-Hotstar.pdf -------------------------------------------------------------------------------- /system design contest/Mihir - LiveBroadcastService.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/system design contest/Mihir - LiveBroadcastService.pdf -------------------------------------------------------------------------------- /system design contest/Vasant - Hotstar System design.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/system design contest/Vasant - Hotstar System design.pdf -------------------------------------------------------------------------------- /system design contest/Guillaume - System design - ESPN.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/system design contest/Guillaume - System design - ESPN.pdf -------------------------------------------------------------------------------- /java-projects/output.txt: -------------------------------------------------------------------------------- 1 | service-log: This 2 | service-log: is 3 | service-log: a 4 | service-log: tutorial 5 | service-log: on 6 | service-log: Dependency 7 | service-log: Injection! 8 | -------------------------------------------------------------------------------- /java-projects/src/main/java/logger/Timer.java: -------------------------------------------------------------------------------- 1 | package logger; 2 | 3 | public class Timer { 4 | public long getCurrentTime() { 5 | return System.currentTimeMillis(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /system design contest/Vasavi - Live video broadcasting system-1.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/system design contest/Vasavi - Live video broadcasting system-1.docx -------------------------------------------------------------------------------- /system design contest/Mincy - Live_video_Streaming_-_sys_design-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-parrot/youtube-projects/HEAD/system design contest/Mincy - Live_video_Streaming_-_sys_design-1.pdf -------------------------------------------------------------------------------- /java-projects/src/main/java/exceptions/LoggingException.java: -------------------------------------------------------------------------------- 1 | package exceptions; 2 | 3 | public class LoggingException extends RuntimeException { 4 | 5 | public LoggingException(Exception e) { 6 | super(e); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /java-projects/src/main/java/logger/Logger.java: -------------------------------------------------------------------------------- 1 | package logger; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | public interface Logger { 6 | 7 | boolean write(String data); 8 | 9 | CompletableFuture flushAsync(); 10 | 11 | boolean close(); 12 | } 13 | -------------------------------------------------------------------------------- /java-projects/src/test/java/TestTimer.java: -------------------------------------------------------------------------------- 1 | import logger.Timer; 2 | 3 | public class TestTimer extends Timer { 4 | 5 | private long currentTime = System.currentTimeMillis(); 6 | 7 | @Override 8 | public long getCurrentTime() { 9 | return currentTime; 10 | } 11 | 12 | public void setCurrentTime(long time) { 13 | currentTime = time; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.idea/projects.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__junit_junit_4_13.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_inject_guice_4_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__aopalliance_aopalliance_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_guava_guava_16_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_inject_javax_inject_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /java-projects/src/main/java/modules/PropertiesModule.java: -------------------------------------------------------------------------------- 1 | package modules; 2 | 3 | import com.google.inject.AbstractModule; 4 | import com.google.inject.name.Names; 5 | 6 | import java.io.IOException; 7 | import java.util.Properties; 8 | 9 | public class PropertiesModule extends AbstractModule { 10 | @Override 11 | public void configure() { 12 | try { 13 | Properties props = new Properties(); 14 | props.load(getClass().getClassLoader().getResourceAsStream("logging.properties")); 15 | Names.bindProperties(binder(), props); 16 | } catch (IOException e) { 17 | throw new RuntimeException(e); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /java-projects/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | import com.google.inject.Guice; 2 | import com.google.inject.Injector; 3 | import modules.LoggingModule; 4 | import modules.PropertiesModule; 5 | 6 | import java.util.concurrent.ExecutionException; 7 | 8 | public class Main { 9 | public static void main(String[] args) { 10 | Injector injector = Guice.createInjector(new PropertiesModule(), new LoggingModule()); 11 | final TaskManager taskManager = injector.getInstance(TaskManager.class); 12 | try { 13 | taskManager.execute().get(); 14 | } catch (InterruptedException | ExecutionException e) { 15 | e.printStackTrace(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /java-projects/src/main/java/TaskManager.java: -------------------------------------------------------------------------------- 1 | import com.google.inject.Inject; 2 | import com.google.inject.Singleton; 3 | import logger.Logger; 4 | 5 | import java.util.concurrent.CompletableFuture; 6 | 7 | @Singleton 8 | public class TaskManager { 9 | private final Logger logger; 10 | 11 | @Inject 12 | public TaskManager(final Logger logger) { 13 | this.logger = logger; 14 | } 15 | 16 | public CompletableFuture execute() { 17 | final String[] sentence = "This is a tutorial on Dependency Injection!".split(" "); 18 | for (final String word : sentence) { 19 | logger.write(word); 20 | } 21 | return logger.flushAsync() 22 | .whenComplete((__, throwable) -> { 23 | if (throwable != null) { 24 | throwable.printStackTrace(); 25 | } else { 26 | logger.close(); 27 | } 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /java-projects/src/main/java/modules/LoggingModule.java: -------------------------------------------------------------------------------- 1 | package modules; 2 | 3 | import com.google.inject.AbstractModule; 4 | import com.google.inject.Provides; 5 | import com.google.inject.name.Named; 6 | import logger.FastLogger; 7 | import logger.Logger; 8 | 9 | import java.io.FileNotFoundException; 10 | import java.io.FileOutputStream; 11 | import java.io.OutputStream; 12 | 13 | 14 | public class LoggingModule extends AbstractModule { 15 | 16 | @Override 17 | public void configure() { 18 | bind(Logger.class).to(FastLogger.class); 19 | } 20 | 21 | @Provides 22 | @Named("file-output-stream") 23 | public OutputStream getOutputStream(@Named("output-file.name") String fileLocation) throws FileNotFoundException { 24 | return new FileOutputStream(fileLocation); 25 | } 26 | 27 | @Provides 28 | @Named("console-output-stream") 29 | public OutputStream getConsoleOutputStream(@Named("output-file.name") String fileLocation) throws FileNotFoundException { 30 | return System.out; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /java-projects/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | java-projects 8 | java-projects 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-compiler-plugin 15 | 16 | 11 17 | 11 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | com.google.inject 26 | guice 27 | 4.0 28 | 29 | 30 | junit 31 | junit 32 | 4.13.1 33 | test 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /java-projects/java-projects.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /git_commands.txt: -------------------------------------------------------------------------------- 1 | mkdir SampleProject 2 | cd SampleProject/ 3 | ls -la 4 | git init 5 | du -c 6 | touch coding.txt 7 | echo I love Coding > coding.txt 8 | cat coding.txt 9 | du -c 10 | git add coding.txt 11 | du -c 12 | ls .git/objects/e6/ 13 | cat .git/objects/e6/90065515b5188b40a5c0df4a975849d1677aea 14 | printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - .git/objects/e6/90065515b5188b40a5c0df4a975849d1677aea |gzip -dc 15 | git cat-file -p e690 16 | git cat-file -s e690 17 | git cat-file -t e690 18 | echo -e 'blob 14I love coding'|shasum 19 | echo -e 'blob 14\0I love coding'|shasum 20 | cd .git/objects/ 21 | git cat-file -p e2adf495f2364725173e5d820faf3a45f87e855c 22 | git cat-file -p 26fed0d0f5f286ed9a8534e3ac32819510e4ef40 23 | cd ../.. 24 | echo some code > coding.txt 25 | cat coding.txt 26 | git commit -am "Wrote some code" 27 | du -c 28 | git cat-file -p e5a9bbd9a4482495e80b4c22861261b9a8004350 29 | git cat-file -p 8d20 30 | git cat-file -t 8d20 31 | git cat-file -s 8d20 32 | git cat-file -p e5a9 33 | git cat-file -s e5a9 34 | git cat-file -t e5a9 35 | printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - .git/objects/e5/a9bbd9a4482495e80b4c22861261b9a8004350 |gzip -dc 36 | cp ~/Desktop/Headshot.png . 37 | git add Headshot.png 38 | du -c 39 | git commit -am "Added Image" 40 | du -c 41 | vim Headshot.png 42 | git commit -am "minor change" 43 | git gc --aggressive 44 | du -c 45 | git verify-pack -v .git/objects/pack/pack-2d6261235fcabfee25186206342f67a6d9d8b42c.idx 46 | git cat-file -s 01b6 47 | git cat-file -s 7f35 48 | The latest file is kept uncompressed to allow faster reads. 49 | git checkout -b my_feature 50 | ls -la .git/refs/heads/my_feature 51 | cat .git/refs/heads/my_feature 52 | git cat-file -p 9c0f 53 | echo lots of code > coding.txt 54 | git commit -am "Wrote lots of code" 55 | git cat-file -p c9d9 56 | -------------------------------------------------------------------------------- /java-projects/src/main/java/logger/SugaredLogger.java: -------------------------------------------------------------------------------- 1 | package logger; 2 | 3 | import com.google.inject.Inject; 4 | import com.google.inject.Singleton; 5 | import com.google.inject.name.Named; 6 | import exceptions.LoggingException; 7 | 8 | import java.io.IOException; 9 | import java.io.OutputStream; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.concurrent.CompletableFuture; 13 | import java.util.concurrent.ExecutorService; 14 | import java.util.concurrent.Executors; 15 | 16 | @Singleton 17 | public class SugaredLogger implements Logger { 18 | private final String identifier; 19 | private final OutputStream stream; 20 | private final List buffer; 21 | 22 | @Inject 23 | public SugaredLogger(final OutputStream stream, @Named("logger.fast.identifier") String identifier) { 24 | this.stream = stream; 25 | this.identifier = identifier; 26 | buffer = new ArrayList<>(); 27 | } 28 | 29 | public boolean write(final String word) { 30 | buffer.add(identifier + " " + word + "\n"); 31 | return true; 32 | } 33 | 34 | public CompletableFuture flushAsync() { 35 | CompletableFuture result = CompletableFuture.completedFuture(null); 36 | ExecutorService service = Executors.newSingleThreadExecutor(); 37 | for (final String word : buffer) { 38 | result = result.thenAcceptAsync(__ -> { 39 | try { 40 | Thread.sleep(1000); 41 | stream.write(word.getBytes()); 42 | } catch (IOException | InterruptedException e) { 43 | e.printStackTrace(); 44 | } 45 | }, service); 46 | } 47 | return result; 48 | } 49 | 50 | public boolean close() { 51 | try { 52 | stream.flush(); 53 | stream.close(); 54 | } catch (IOException e) { 55 | throw new LoggingException(e); 56 | } 57 | return false; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /java-projects/src/main/java/logger/FastLogger.java: -------------------------------------------------------------------------------- 1 | package logger; 2 | 3 | import com.google.inject.Inject; 4 | import com.google.inject.Singleton; 5 | import com.google.inject.name.Named; 6 | import exceptions.LoggingException; 7 | 8 | import java.io.IOException; 9 | import java.io.OutputStream; 10 | import java.util.concurrent.CompletableFuture; 11 | 12 | @Singleton 13 | public class FastLogger implements Logger { 14 | private final String identifier; 15 | private final OutputStream stream; 16 | private final byte[] buffer; 17 | private int currentSize; 18 | 19 | @Inject 20 | public FastLogger(@Named("logger.fast.identifier") final String identifier, 21 | @Named("console-output-stream") final OutputStream stream, 22 | @Named("logger.fast.buffer.size") final Integer bufferSize) { 23 | this.identifier = identifier; 24 | this.stream = stream; 25 | this.buffer = new byte[bufferSize]; 26 | this.currentSize = 0; 27 | } 28 | 29 | 30 | private void flush() { 31 | try { 32 | stream.write(buffer); 33 | stream.flush(); 34 | currentSize = 0; 35 | } catch (IOException e) { 36 | throw new LoggingException(e); 37 | } 38 | } 39 | 40 | @Override 41 | public boolean write(final String data) { 42 | final byte[] bytes = (identifier + " " + data + "\n").getBytes(); 43 | if (currentSize + bytes.length > buffer.length) { 44 | return false; 45 | } 46 | System.arraycopy(bytes, 0, buffer, currentSize, bytes.length); 47 | currentSize += bytes.length; 48 | return true; 49 | } 50 | 51 | @Override 52 | public CompletableFuture flushAsync() { 53 | return CompletableFuture.runAsync(this::flush); 54 | } 55 | 56 | @Override 57 | public boolean close() { 58 | try { 59 | stream.flush(); 60 | stream.close(); 61 | } catch (IOException e) { 62 | throw new LoggingException(e); 63 | } 64 | return false; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Transformer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //AppDetails stores the application details, for every userId 8 | type AppDetails map[string]UserDetails 9 | 10 | //UserDetails stores the device details of this user, for every deviceId 11 | type UserDetails map[string]DeviceDetails 12 | 13 | //DeviceDetails stores the timeUsed on this device, for every location 14 | type DeviceDetails map[string]int 15 | 16 | func main() { 17 | var ad AppDetails = AppDetails{} 18 | var ud UserDetails = UserDetails{} 19 | var androidDetails DeviceDetails = DeviceDetails{} 20 | androidDetails["Hyderabad"] = 20 21 | androidDetails["Mumbai"] = 12 22 | androidDetails["Chennai"] = 35 23 | var macDetails DeviceDetails = DeviceDetails{} 24 | macDetails["Delhi"] = 30 25 | macDetails["Mumbai"] = 10 26 | macDetails["Hyderabad"] = 17 27 | ud["android"] = androidDetails 28 | ud["mac"] = macDetails 29 | ad["gaurav.sen"] = ud 30 | fmt.Println(Transform(&ad)) 31 | 32 | unknownDeviceDetails := DeviceDetails{} 33 | unknownDeviceDetails["Hyderabad"] = 90 34 | unknownDeviceDetails[""] = 12 35 | unknownUserDetails := UserDetails{} 36 | unknownUserDetails[""] = unknownDeviceDetails 37 | ad[""] = unknownUserDetails 38 | param := make(map[string]interface{}) 39 | for k, v := range ad { 40 | param[k] = v 41 | } 42 | fmt.Println(GraphSearch(param, 0)) 43 | } 44 | 45 | //Transform populates a map iteratively 46 | func Transform(co *AppDetails) map[string]map[string]map[string]int { 47 | result := make(map[string]map[string]map[string]int) 48 | for username, userDetails := range *co { 49 | if username == "" { 50 | username = "John Doe" 51 | } 52 | result[username] = make(map[string]map[string]int) 53 | for device, deviceDetails := range userDetails { 54 | if device == "" { 55 | device = "Unknown" 56 | } 57 | result[username][device] = make(map[string]int) 58 | for location, timeUsed := range deviceDetails { 59 | if location == "" { 60 | location = "Unknown" 61 | } 62 | if timeUsed > 10 { 63 | result[username][device][location] = timeUsed 64 | } 65 | } 66 | } 67 | } 68 | return result 69 | } 70 | 71 | var keys = []string{"username", "device", "location"} 72 | 73 | // GraphSearch populates a map recursively 74 | func GraphSearch(dataSlice map[string]interface{}, level int) map[string]interface{} { 75 | result := make(map[string]interface{}) 76 | if level == len(keys)-1 { 77 | for baseAttributeKey, baseAttributeValue := range dataSlice { 78 | result[baseAttributeKey], _ = baseAttributeValue.(int) 79 | } 80 | } else { 81 | for attributeKey, details := range dataSlice { 82 | attributeDetails := details.(map[string]interface{}) 83 | result[attributeKey] = GraphSearch(attributeDetails, level+1) 84 | } 85 | } 86 | return result 87 | } -------------------------------------------------------------------------------- /java-projects/src/test/java/LoggerTest.java: -------------------------------------------------------------------------------- 1 | import logger.LogClient; 2 | import logger.LogClientImpl; 3 | import org.junit.Test; 4 | 5 | import java.util.*; 6 | import java.util.concurrent.*; 7 | 8 | import static java.util.concurrent.CompletableFuture.allOf; 9 | import static java.util.concurrent.CompletableFuture.runAsync; 10 | 11 | public class LoggerTest { 12 | @Test 13 | public void defaultLogging() throws InterruptedException, ExecutionException { 14 | final LogClient logClient = new LogClientImpl(10); 15 | List> tasks = new ArrayList<>(); 16 | logClient.start("1", 1); 17 | logClient.start("2", 2); 18 | logClient.start("3", 3); 19 | logClient.end("3"); 20 | logClient.end("2"); 21 | tasks.add(runAsync(logClient::poll)); 22 | tasks.add(runAsync(logClient::poll)); 23 | logClient.end("1"); 24 | tasks.add(runAsync(logClient::poll)); 25 | allOf(tasks.toArray(CompletableFuture[]::new)).get(); 26 | } 27 | 28 | @Test 29 | public void concurrencyTest() throws ExecutionException, InterruptedException { 30 | final LogClient logClient = new LogClientImpl(10); 31 | final var size = 1000; 32 | final ExecutorService executorService = Executors.newFixedThreadPool(size); 33 | final Random random = new Random(); 34 | final List commands = new ArrayList<>(); 35 | for (int i = 0; i < size; i++) { 36 | commands.add("POLL"); 37 | commands.add("END " + i); 38 | } 39 | Collections.shuffle(commands); 40 | Map ends = new HashMap<>(); 41 | for (int i = 0; i < size * 2; i++) { 42 | if (!commands.get(i).equals("POLL")) { 43 | ends.put(Integer.parseInt(commands.get(i).split(" ")[1]), i); 44 | } 45 | } 46 | int index = commands.size() - 1; 47 | while (index >= 0) { 48 | if (commands.get(index).startsWith("END ")) { 49 | final var taskId = Integer.parseInt(commands.get(index).split(" ")[1]); 50 | final var insertionPoint = random.nextInt(Math.min(ends.get(taskId), ends.getOrDefault(taskId + 1, commands.size() - 1)) + 1); 51 | commands.add(insertionPoint, "START " + taskId); 52 | if (insertionPoint <= index) { 53 | index++; 54 | } 55 | } 56 | index--; 57 | } 58 | final List> tasks = new CopyOnWriteArrayList<>(); 59 | for (final String command : commands) { 60 | if (command.equals("POLL")) { 61 | tasks.add(runAsync(logClient::poll, executorService)); 62 | } else { 63 | final var id = command.split(" ")[1]; 64 | if (command.startsWith("START ")) { 65 | logClient.start(id, size - Long.parseLong(id) + 1); 66 | } else { 67 | logClient.end(id); 68 | } 69 | } 70 | } 71 | allOf(tasks.toArray(CompletableFuture[]::new)).get(); 72 | } 73 | } -------------------------------------------------------------------------------- /java-projects/src/main/java/logger/LogClientImpl.java: -------------------------------------------------------------------------------- 1 | package logger; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.concurrent.*; 6 | import java.util.concurrent.locks.Lock; 7 | import java.util.concurrent.locks.ReentrantLock; 8 | 9 | public class LogClientImpl implements LogClient { 10 | private final ConcurrentSkipListMap> queue; 11 | private final Map map; 12 | private final Lock lock; 13 | private final BlockingQueue> pendingPolls; 14 | private final ExecutorService[] executorService; 15 | 16 | public LogClientImpl(int threads) { 17 | queue = new ConcurrentSkipListMap<>(); 18 | map = new ConcurrentHashMap<>(); 19 | lock = new ReentrantLock(); 20 | pendingPolls = new LinkedBlockingQueue<>(); 21 | executorService = new ExecutorService[threads]; 22 | for (int i = 0; i < executorService.length; i++) { 23 | executorService[i] = Executors.newSingleThreadExecutor(); 24 | } 25 | } 26 | 27 | public void start(final String taskId, long timestamp) { 28 | executorService[taskId.hashCode() % executorService.length].execute(() -> { 29 | final Process task = new Process(taskId, timestamp); 30 | map.put(taskId, task); 31 | queue.putIfAbsent(timestamp, new CopyOnWriteArrayList<>()); 32 | queue.get(timestamp).add(task); 33 | }); 34 | } 35 | 36 | public void end(final String taskId) { 37 | executorService[taskId.hashCode() % executorService.length].execute(() -> { 38 | map.get(taskId).setEndTime(System.currentTimeMillis()); 39 | lock.lock(); 40 | try { 41 | String result; 42 | while (!pendingPolls.isEmpty() && (result = pollNow()) != null) { 43 | pendingPolls.take().complete(result); 44 | } 45 | } catch (InterruptedException e) { 46 | e.printStackTrace(); 47 | } finally { 48 | lock.unlock(); 49 | } 50 | }); 51 | } 52 | 53 | public String poll() { 54 | final CompletableFuture result = new CompletableFuture<>(); 55 | lock.lock(); 56 | try { 57 | try { 58 | String logStatement; 59 | if (!pendingPolls.isEmpty()) { 60 | pendingPolls.offer(result); 61 | } else if ((logStatement = pollNow()) != null) { 62 | return logStatement; 63 | } else { 64 | pendingPolls.offer(result); 65 | } 66 | } finally { 67 | lock.unlock(); 68 | } 69 | return result.get(10, TimeUnit.SECONDS); 70 | } catch (InterruptedException | ExecutionException | TimeoutException e) { 71 | throw new RuntimeException(e); 72 | } 73 | } 74 | 75 | private String pollNow() { 76 | if (!queue.isEmpty()) { 77 | for (final Process earliest : queue.firstEntry().getValue()) { 78 | if (earliest.getEndTime() != -1) { 79 | queue.firstEntry().getValue().remove(earliest); 80 | if (queue.firstEntry().getValue().isEmpty()) { 81 | queue.pollFirstEntry(); 82 | } 83 | map.remove(earliest.getId()); 84 | final var logStatement = "task " + earliest.getId() + " started at: " + earliest.getStartTime() + " and ended at: " + earliest.getEndTime(); 85 | System.out.println(logStatement); 86 | return logStatement; 87 | } 88 | } 89 | } 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /java-projects/src/main/java/logger/LogClient.java: -------------------------------------------------------------------------------- 1 | package logger; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.*; 5 | import java.util.concurrent.locks.Lock; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | public interface LogClient { 9 | /** 10 | * When a process starts, it calls 'start' with processId. 11 | */ 12 | void start(String processId, long timestamp); 13 | 14 | /** 15 | * When the same process ends, it calls 'end' with processId. 16 | */ 17 | void end(String processId); 18 | 19 | /** 20 | * Polls the first log entry of a completed process sorted by the start time of processes in the below format 21 | * {processId} started at {startTime} and ended at {endTime} 22 | *

23 | * process id = 1 --> 12, 15 24 | * process id = 2 --> 8, 12 25 | * process id = 3 --> 7, 19 26 | *

27 | * {3} started at {7} and ended at {19} 28 | * {2} started at {8} and ended at {12} 29 | * {1} started at {12} and ended at {15} 30 | */ 31 | String poll(); 32 | } 33 | 34 | class LoggerImplementation implements LogClient { 35 | 36 | private final Map processes; 37 | private final ConcurrentSkipListMap queue; 38 | private final List> futures; 39 | private final Lock lock; 40 | private final ExecutorService[] taskScheduler; 41 | 42 | public LoggerImplementation() { 43 | this.processes = new ConcurrentHashMap<>(); 44 | this.queue = new ConcurrentSkipListMap<>(); 45 | this.futures = new CopyOnWriteArrayList<>(); 46 | this.lock = new ReentrantLock(); 47 | this.taskScheduler = new ExecutorService[10]; 48 | for (int i = 0; i < taskScheduler.length; i++) { 49 | taskScheduler[i] = Executors.newSingleThreadExecutor(); 50 | } 51 | } 52 | 53 | @Override 54 | public void start(String processId, long timestamp) { //1 55 | taskScheduler[processId.hashCode() % taskScheduler.length].execute(() -> { 56 | final Process process = new Process(processId, timestamp); 57 | processes.put(processId, process); 58 | queue.put(timestamp, process); 59 | }); 60 | } 61 | 62 | @Override 63 | public void end(String processId) { //1 64 | taskScheduler[processId.hashCode() % taskScheduler.length].execute(() -> { 65 | lock.lock();//1 66 | try { 67 | final long now = System.currentTimeMillis();//1 68 | processes.get(processId).setEndTime(now);//1 69 | if (!futures.isEmpty() && queue.firstEntry().getValue().getId().equals(processId)) { 70 | pollNow(); 71 | final var result = futures.remove(0); 72 | result.complete(null); 73 | } 74 | } finally { 75 | lock.unlock(); 76 | } 77 | }); 78 | } 79 | 80 | @Override 81 | public String poll() { 82 | lock.lock(); 83 | try { 84 | final var result = new CompletableFuture(); 85 | if (!queue.isEmpty() && queue.firstEntry().getValue().getEndTime() != -1) { 86 | pollNow(); 87 | } else { 88 | futures.add(result); 89 | } 90 | try { 91 | result.get(3, TimeUnit.SECONDS); 92 | } catch (InterruptedException | ExecutionException | TimeoutException e) { 93 | throw new RuntimeException(e); 94 | } 95 | return null; 96 | } finally { 97 | lock.unlock(); 98 | } 99 | } 100 | 101 | private String pollNow() { 102 | final Process process = queue.firstEntry().getValue(); 103 | final var logStatement = process.getId() + " started at " + process.getStartTime() + " and ended at " + process.getEndTime(); 104 | System.out.println(logStatement); 105 | processes.remove(process.getId()); 106 | queue.pollFirstEntry(); 107 | return logStatement; 108 | } 109 | } 110 | 111 | class Process { 112 | private final String id; 113 | private final long startTime; 114 | private long endTime; 115 | 116 | public Process(final String id, final long startTime) { 117 | this.id = id; 118 | this.startTime = startTime; 119 | endTime = -1; 120 | } 121 | 122 | public String getId() { 123 | return id; 124 | } 125 | 126 | public long getStartTime() { 127 | return startTime; 128 | } 129 | 130 | public long getEndTime() { 131 | return endTime; 132 | } 133 | 134 | public void setEndTime(long endTime) { 135 | this.endTime = endTime; 136 | } 137 | } 138 | 139 | class LoggerMain { 140 | /* 141 | * {3} started at {7} and ended at {19} 142 | * {2} started at {8} and ended at {12} 143 | * {1} started at {12} and ended at {15} 144 | */ 145 | public static void main(String[] args) { 146 | final LogClient logger = new LoggerImplementation(); 147 | logger.start("1", 1); 148 | logger.poll(); 149 | logger.start("3", 2); 150 | logger.poll(); 151 | logger.end("1"); 152 | logger.poll(); 153 | logger.start("2", 3); 154 | logger.poll(); 155 | logger.end("2"); 156 | logger.poll(); 157 | logger.end("3"); 158 | logger.poll(); 159 | logger.poll(); 160 | logger.poll(); 161 | //1 162 | //3 163 | //2 164 | } 165 | } -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | --------------------------------------------------------------------------------