/*
具体实现理论参见 mongodb官方  objectid生成策略
http://docs.mongodb.org/manual/reference/object-id/
ObjectId 是一个由12字节组成的bson数据,按照字节顺序,一次代表:
ObjectId is a 12-byte BSON type, constructed using:
4个字节代表1970年元月一日到现在毫秒数  UNIX时间戳
a 4-byte value representing the seconds since the Unix epoch,
3个字节代表机器的唯一标识符    表示运行的机器
a 3-byte machine identifier,
2个字节代表进程的id 表示生成此_id的进程
a 2-byte process id, and
3个字节代表计数器,开始带着一个随机数   由一个随机数开始的计数器生成的值
a 3-byte counter, starting with a random value.

*/

package objectid

import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "math/rand"
    "os"
    "sync/atomic"
    "time"
)

var staticMachine = getMachineHash()  //获取机器的id
var staticIncrement = getRandomNumber()//获取随机数
var staticPid = int32(os.Getpid())//获取进程id
//
type ObjectId struct {
    timestamp int64
    machine   int32
    pid       int32
    increment int32
}
//
func New() *ObjectId {
    timestamp := time.Now().Unix()
    return &ObjectId{timestamp, staticMachine, staticPid, atomic.AddInt32(&staticIncrement, 1) & 0xffffff}
}
//
func Parse(input string) *ObjectId {
    if len(input) == 0 {
        panic("The input is empty.")
    }
    if value, ok := tryParse(input); ok {
        return value
    }
    panic(fmt.Sprintf("%s is not a valid 24 digit hex string.", input))
}
//
func (this *ObjectId) Timestamp() int64 {
    return this.timestamp
}
//
func (this *ObjectId) Machine() int32 {
    return this.machine
}
//
func (this *ObjectId) Pid() int32 {
    return this.pid
}
//
func (this *ObjectId) Increment() int32 {
    return this.increment & 0xffffff
}
//
func (this *ObjectId) CreationTime() time.Time {
    return time.Unix(this.timestamp, 0)
}
//
func (this *ObjectId) Equal(other *ObjectId) bool {
    return this.timestamp == other.timestamp &&
        this.machine == other.machine &&
        this.pid == other.pid &&
        this.increment == other.increment
}
//
func (this *ObjectId) String() string {
    array := []byte{
        byte(this.timestamp >> 0x18),
        byte(this.timestamp >> 0x10),
        byte(this.timestamp >> 8),
        byte(this.timestamp),
        byte(this.machine >> 0x10),
        byte(this.machine >> 8),
        byte(this.machine),
        byte(this.pid >> 8),
        byte(this.pid),
        byte(this.increment >> 0x10),
        byte(this.increment >> 8),
        byte(this.increment),
    }
    return hex.EncodeToString(array)
}
//获取机器唯一标识符
func getMachineHash() int32 {
    machineName, err := os.Hostname()
    if err != nil {
        panic(err)
    }
    buf := md5.Sum([]byte(machineName))
    return (int32(buf[0])<<0x10 + int32(buf[1])<<8) + int32(buf[2])
}
//获取随机数开始的计数器生成的值
func getRandomNumber() int32 {
    rand.Seed(time.Now().UnixNano())
    return rand.Int31()
}
//从字符串objectid  解析成为ObjectId
func tryParse(input string) (*ObjectId, bool) {
    if len(input) != 0x18 {
        return nil, false
    }
    array, err := hex.DecodeString(input) //十六进制的字符串 转化为字节切片 
    if err != nil {
        return nil, false
    }
    return &ObjectId{
        timestamp: int64(array[0])<<0x18 + int64(array[1])<<0x10 + int64(array[2])<<8 + int64(array[3]),
               //转化为十进制的int64  新纪元时间  毫秒
        machine:   int32(array[4])<<0x10 + int32(array[5])<<8 + int32(array[6]),
               //转化为十进制的int32数据   机器唯一标识符
        pid:       int32(array[7])<<8 + int32(array[8]),
              // 当前进程id
        increment: int32(array[9])<<0x10 + (int32(array[10]) << 8) + int32(array[11]),
              // 随机数开始的计数器生成的值
    }, true
}

objectid.go源码阅读的更多相关文章

  1. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  2. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  3. 【原】FMDB源码阅读(一)

    [原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...

  4. 【原】AFNetworking源码阅读(六)

    [原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...

  5. 【原】AFNetworking源码阅读(五)

    [原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...

  6. 【原】AFNetworking源码阅读(四)

    [原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...

  7. 【原】AFNetworking源码阅读(三)

    [原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...

  8. 【原】AFNetworking源码阅读(二)

    [原]AFNetworking源码阅读(二) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中我们在iOS Example代码中提到了AFHTTPSessionMa ...

  9. 【原】AFNetworking源码阅读(一)

    [原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...

随机推荐

  1. asp.net 下的中文分词检索工具 - jieba.net

    jieba是python下的一个检索库, 有人将这个库移植到了asp.net 平台下, 完全可以替代lucene.net以及盘古分词的搭配 之所以写这个, 其实是因为昨天面试时, 被问到网站的关键字检 ...

  2. .Net C# 串口 Serialort safe handle has been closed 问题的解决

    最近在一个平台上使用SerialPort类开发程序时,发现程序在使用SerialPort类时会异常退出,而且诡异的是,就算把所有操作串口的代码都放在try{}catch{}块中也无法捕获这个异常.最终 ...

  3. 关于eclipse运行TestNG出现: CreateProcess error=206, ÎļþÃû»ò)չÃû的解决办法

    最近玩物流宝的一个项目,需要测试下3个系统打通的接口. 不测不要紧,一测吓一跳.我的乖乖:几百个bean被加进来.就凭我这肉机,内存不爆才怪. 于是换一套方案,用了另一个测试接口. 但是这个测试接口, ...

  4. 安装 Anaconda 的正确姿势

    下面以 Anaconda2 安装为例, 说明如何更加流畅的使用 Conda Install Anaconda2 安装 Anaconda2(从清华源下载比较快) wget https://mirrors ...

  5. Spring Boot开发MongoDB应用实践

    本文继续上一篇定时任务中提到的邮件服务,简单讲解Spring Boot中如何使用MongoDB进行应用开发. 上文中提到的这个简易邮件系统大致设计思路如下: 1.发送邮件支持同步和异步发送两种 2.邮 ...

  6. nginx 反向代理,支持跨域,前后分离

    前端开发往往涉及到跨域问题,其中解决方案很多: 1.jsonp 需要目标服务器配合一个callback函数. 2.window.name+iframe 需要目标服务器响应window.name. 3. ...

  7. 在Django中使用Neo4j

    重要的先说在前面吧,最后的选型结构是安装了最新的neo4j版本3.0.3,使用了neo4j-rest-client客户端库.主要原因是更适用于django的neomodel库目前只支持neo4j2.2 ...

  8. Java main方法全解

    1.main方法的重载 package cn.nxl2018; public class Main_test { public static void main(String args[]) { Sy ...

  9. 启动eclipse时候提示错误Error:Could not create the Java Virtual Machine. Error:A Fatal exception has occurred,Program will exit.

    我的是neon3版本 解决办法是: 首先把这两个选项勾选,才能看到eclipse.ini完整的文件名.然后用记事本等工具打开编辑. 新版的里面原本是这样: -startup plugins/org.e ...

  10. ExtJs radiogroup form.loadRecord方法无法赋值正确解决办法

    一.radiogroup的name和radio的name一致,inputValue为整形 { xtype: 'radiogroup', fieldLabel: '是否有效', name: 'statu ...